基于socket实现http上传
This commit is contained in:
parent
e94c452962
commit
9d13c4228a
|
@ -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;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue