基于socket实现http上传

This commit is contained in:
luoliangyi 2022-05-10 18:23:13 +08:00
parent e94c452962
commit 9d13c4228a
3 changed files with 3001 additions and 1 deletions

View File

@ -1557,12 +1557,187 @@ bool Manager::SaveBase64(const std::string& fileName, const char* base64)
return ret; return ret;
} }
static std::string MakePreFileData(const char* pszBoundary, const char* pszRemoteFileName)
{
char data[512];
sprintf(data, "--%s\r\nContent-Disposition: form-data; name=\"filedata\"; filename=\"%s\"\r\n",
pszBoundary, pszRemoteFileName);
std::string ret = data;
ret += "Content-Type: application/octet-stream; charset=utf-8\r\n";
ret += "Content-Transfer-Encoding: binary\r\n";
ret += "\r\n";
return ret;
}
static std::string MakePostFileData(const char* pszBoundary)
{
char data[512];
sprintf(data, "\r\n--%s\r\nContent-Disposition: form-data; name=\"submitted\"\r\n\r\nsubmit\r\n--%s--\r\n", pszBoundary, pszBoundary);
return data;
}
static void ParseHttpURL(const std::string &url, std::string &addr, int &port, std::string &path)
{
addr.clear();
port = 0;
path.clear();
std::string url2;
std::string::size_type pos = url.find("//");
if (std::string::npos != pos)
{
std::string protocal = url.substr(0, pos);
if (protocal != "http:")
{
return;
}
url2 = url.substr(pos + 2);
}
else
{
url2 = url;
}
std::string addr_port;
pos = url2.find("/");
if (std::string::npos != pos)
{
addr_port = url2.substr(0, pos);
path = url2.substr(pos);
}
else
{
addr_port = url2;
}
pos = addr_port.find(":");
if (std::string::npos != pos)
{
addr = addr_port.substr(0, pos);
port = atoi(addr_port.substr(pos + 1).c_str());
}
else
{
addr = addr_port;
port = 80;
}
}
bool Manager::HTTPUpload(const std::string& localFileName, const std::string& httpUrl, const std::string& remoteFileName, bool Manager::HTTPUpload(const std::string& localFileName, const std::string& httpUrl, const std::string& remoteFileName,
const std::string& httpMethod, const std::string& header, const std::string& param) const std::string& httpMethod, const std::string& header, const std::string& param)
{
unsigned char* fileData = NULL;
long fileSize = 0;
FILE* file = fopen(localFileName.c_str(), "rb");
if (NULL != file)
{
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
if (0 != fileSize)
{
fileData = new unsigned char[fileSize];
fread(fileData, 1, fileSize, file);
}
fclose(file);
}
if (NULL == fileData)
{ {
return false; return false;
} }
std::string addr;
int port;
std::string path;
ParseHttpURL(httpUrl, addr, port, path);
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
assert(INVALID_SOCKET != sockClient);
u_long ul = 1; // 设为非阻塞
ioctlsocket(sockClient, FIONBIO, &ul);
SOCKADDR_IN addrServer = { 0 };
addrServer.sin_addr.S_un.S_addr = inet_addr(addr.c_str());
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(port);
if (0 != connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR_IN)))
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(sockClient, &fds);
timeval tm;
tm.tv_sec = 1;
tm.tv_usec = 0;
if (select((int)(sockClient + 1), NULL, &fds, NULL, &tm) <= 0)
{
closesocket(sockClient);
delete[] fileData;
return false;
}
if (!FD_ISSET(sockClient, &fds))
{
closesocket(sockClient);
delete[] fileData;
return false;
}
}
ul = 0; // 设为阻塞
ioctlsocket(sockClient, FIONBIO, &ul);
char remoteName[256];
HGBase_GetFileName(localFileName.c_str(), remoteName, 256);
bool ret = false;
const char* pszBoundary = "---------------------------7d33a816d302b6";
std::string strPreFileData = MakePreFileData(pszBoundary, remoteName);
std::string strPostFileData = MakePostFileData(pszBoundary);
char hostname[128];
gethostname(hostname, 128);
std::string head;
char data[512];
sprintf(data, "POST %s HTTP/1.1\r\nHost: %s\r\n", path.c_str(), hostname);
head += data;
sprintf(data, "Content-Type: multipart/form-data; boundary=%s\r\n", pszBoundary);
head += data;
sprintf(data, "Content-Length: %d\r\n\r\n", strPreFileData.size() + fileSize + strPostFileData.size());
head += data;
send(sockClient, head.c_str(), head.size(), 0);
send(sockClient, strPreFileData.c_str(), strPreFileData.size(), 0);
send(sockClient, (const char *)fileData, fileSize, 0);
send(sockClient, strPostFileData.c_str(), strPostFileData.size(), 0);
char recvBuf[2048] = {0};
recv(sockClient, recvBuf, 2048, 0);
std::string strRecv(recvBuf);
std::string::size_type pos = strRecv.find("\r\n");
if (pos != std::string::npos)
{
std::string head = strRecv.substr(0, pos);
if (head.find("200") != std::string::npos)
{
ret = true;
}
}
closesocket(sockClient);
delete[] fileData;
return ret;
}
static size_t read_callback(char* ptr, size_t size, size_t nmemb, void* stream) static size_t read_callback(char* ptr, size_t size, size_t nmemb, void* stream)
{ {
unsigned long nread; unsigned long nread;

2576
third_party/cgic/cgic.c vendored Normal file

File diff suppressed because it is too large Load Diff

249
third_party/cgic/cgic.h vendored Normal file
View File

@ -0,0 +1,249 @@
/* The CGI_C library, by Thomas Boutell, version 2.01. CGI_C is intended
to be a high-quality API to simplify CGI programming tasks. */
/* Make sure this is only included once. */
#ifndef CGI_C
#define CGI_C 1
/* Ensure proper linkage to c++ programs. */
#ifdef __cplusplus
extern "C" {
#endif
/* Bring in standard I/O since some of the functions refer to
types defined by it, such as FILE *. */
#include <stdio.h>
/* The various CGI environment variables. Instead of using getenv(),
the programmer should refer to these, which are always
valid null-terminated strings (they may be empty, but they
will never be null). If these variables are used instead
of calling getenv(), then it will be possible to save
and restore CGI environments, which is highly convenient
for debugging. */
extern char *cgiServerSoftware;
extern char *cgiServerName;
extern char *cgiGatewayInterface;
extern char *cgiServerProtocol;
extern char *cgiServerPort;
extern char *cgiRequestMethod;
extern char *cgiPathInfo;
extern char *cgiPathTranslated;
extern char *cgiScriptName;
extern char *cgiQueryString;
extern char *cgiRemoteHost;
extern char *cgiRemoteAddr;
extern char *cgiAuthType;
extern char *cgiRemoteUser;
extern char *cgiRemoteIdent;
extern char *cgiContentType;
extern char *cgiAccept;
extern char *cgiUserAgent;
extern char *cgiReferrer;
/* Cookies as sent to the server. You can also get them
individually, or as a string array; see the documentation. */
extern char *cgiCookie;
/* A macro providing the same incorrect spelling that is
found in the HTTP/CGI specifications */
#define cgiReferer cgiReferrer
/* The number of bytes of data received.
Note that if the submission is a form submission
the library will read and parse all the information
directly from cgiIn; the programmer need not do so. */
extern int cgiContentLength;
/* Pointer to CGI output. The cgiHeader functions should be used
first to output the mime headers; the output HTML
page, GIF image or other web document should then be written
to cgiOut by the programmer. In the standard CGIC library,
cgiOut is always equivalent to stdout. */
extern FILE *cgiOut;
/* Pointer to CGI input. The programmer does not read from this.
We have continued to export it for backwards compatibility
so that cgic 1.x applications link properly. */
extern FILE *cgiIn;
/* Possible return codes from the cgiForm family of functions (see below). */
typedef enum {
cgiFormSuccess,
cgiFormTruncated,
cgiFormBadType,
cgiFormEmpty,
cgiFormNotFound,
cgiFormConstrained,
cgiFormNoSuchChoice,
cgiFormMemory,
cgiFormNoFileName,
cgiFormNoContentType,
cgiFormNotAFile,
cgiFormOpenFailed,
cgiFormIO,
cgiFormEOF
} cgiFormResultType;
/* These functions are used to retrieve form data. See
cgic.html for documentation. */
extern cgiFormResultType cgiFormString(
char *name, char *result, int max);
extern cgiFormResultType cgiFormStringNoNewlines(
char *name, char *result, int max);
extern cgiFormResultType cgiFormStringSpaceNeeded(
char *name, int *length);
extern cgiFormResultType cgiFormStringMultiple(
char *name, char ***ptrToStringArray);
extern void cgiStringArrayFree(char **stringArray);
extern cgiFormResultType cgiFormInteger(
char *name, int *result, int defaultV);
extern cgiFormResultType cgiFormIntegerBounded(
char *name, int *result, int min, int max, int defaultV);
extern cgiFormResultType cgiFormDouble(
char *name, double *result, double defaultV);
extern cgiFormResultType cgiFormDoubleBounded(
char *name, double *result, double min, double max, double defaultV);
extern cgiFormResultType cgiFormSelectSingle(
char *name, char **choicesText, int choicesTotal,
int *result, int defaultV);
extern cgiFormResultType cgiFormSelectMultiple(
char *name, char **choicesText, int choicesTotal,
int *result, int *invalid);
/* Just an alias; users have asked for this */
#define cgiFormSubmitClicked cgiFormCheckboxSingle
extern cgiFormResultType cgiFormCheckboxSingle(
char *name);
extern cgiFormResultType cgiFormCheckboxMultiple(
char *name, char **valuesText, int valuesTotal,
int *result, int *invalid);
extern cgiFormResultType cgiFormRadio(
char *name, char **valuesText, int valuesTotal,
int *result, int defaultV);
/* The paths returned by this function are the original names of files
as reported by the uploading web browser and shoult NOT be
blindly assumed to be "safe" names for server-side use! */
extern cgiFormResultType cgiFormFileName(
char *name, char *result, int max);
/* The content type of the uploaded file, as reported by the browser.
It should NOT be assumed that browsers will never falsify
such information. */
extern cgiFormResultType cgiFormFileContentType(
char *name, char *result, int max);
extern cgiFormResultType cgiFormFileSize(
char *name, int *sizeP);
typedef struct cgiFileStruct *cgiFilePtr;
extern cgiFormResultType cgiFormFileOpen(
char *name, cgiFilePtr *cfpp);
extern cgiFormResultType cgiFormFileRead(
cgiFilePtr cfp, char *buffer, int bufferSize, int *gotP);
extern cgiFormResultType cgiFormFileClose(
cgiFilePtr cfp);
extern cgiFormResultType cgiCookieString(
char *name, char *result, int max);
extern cgiFormResultType cgiCookieInteger(
char *name, int *result, int defaultV);
cgiFormResultType cgiCookies(
char ***ptrToStringArray);
typedef enum {
cgiCookieSecure = 1,
cgiCookieHttpOnly = 2,
cgiCookieSameSiteStrict = 4
} cgiCookieOption;
/* path can be null or empty in which case a path of / (entire site) is set.
domain can be a single web site; if it is an entire domain, such as
'boutell.dev', it should begin with a dot: '.boutell.dev' */
extern void cgiHeaderCookieSet(char *name, char *value,
int secondsToLive, char *path, char *domain, int options);
extern void cgiHeaderCookieSetString(char *name, char *value,
int secondsToLive, char *path, char *domain);
extern void cgiHeaderCookieSetInteger(char *name, int value,
int secondsToLive, char *path, char *domain);
extern void cgiHeaderLocation(char *redirectUrl);
extern void cgiHeaderStatus(int status, char *statusMessage);
extern void cgiHeaderContentType(char *mimeType);
typedef enum {
cgiEnvironmentIO,
cgiEnvironmentMemory,
cgiEnvironmentSuccess,
cgiEnvironmentWrongVersion
} cgiEnvironmentResultType;
extern cgiEnvironmentResultType cgiWriteEnvironment(char *filename);
extern cgiEnvironmentResultType cgiReadEnvironment(char *filename);
extern int cgiMain();
extern cgiFormResultType cgiFormEntries(
char ***ptrToStringArray);
/* Output string with the <, &, and > characters HTML-escaped.
's' is null-terminated. Returns cgiFormIO in the event
of error, cgiFormSuccess otherwise. */
cgiFormResultType cgiHtmlEscape(const char *s);
/* Output data with the <, &, and > characters HTML-escaped.
'data' is not null-terminated; 'len' is the number of
bytes in 'data'. Returns cgiFormIO in the event
of error, cgiFormSuccess otherwise. */
cgiFormResultType cgiHtmlEscapeData(const char *data, int len);
/* Output string with the " character HTML-escaped, and no
other characters escaped. This is useful when outputting
the contents of a tag attribute such as 'href' or 'src'.
's' is null-terminated. Returns cgiFormIO in the event
of error, cgiFormSuccess otherwise. */
cgiFormResultType cgiValueEscape(const char *s);
/* Output data with the " character HTML-escaped, and no
other characters escaped. This is useful when outputting
the contents of a tag attribute such as 'href' or 'src'.
'data' is not null-terminated; 'len' is the number of
bytes in 'data'. Returns cgiFormIO in the event
of error, cgiFormSuccess otherwise. */
cgiFormResultType cgiValueEscapeData(const char *data, int len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CGI_C */