Core: HttpRequest multipart support

git-svn-id: svn://ultimatepp.org/upp/trunk@6158 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2013-06-29 18:52:38 +00:00
parent 243ed78eb3
commit 54be50c44c
6 changed files with 47 additions and 8 deletions

View file

@ -118,6 +118,25 @@ HttpRequest& HttpRequest::Post(const char *id, const String& data)
return *this;
}
HttpRequest& HttpRequest::Part(const char *id, const String& data,
const char *content_type, const char *filename)
{
if(IsNull(multipart)) {
POST();
multipart = AsString(Uuid::Create());
ContentType("multipart/form-data; boundary=" + multipart);
}
postdata << "--" << multipart << "\r\n"
<< "Content-Disposition: form-data; name=\"" << id << "\"";
if(filename && *filename)
postdata << "; filename=\"" << filename << "\"";
postdata << "\r\n";
if(content_type && *content_type)
postdata << "Content-Type: " << content_type << "\r\n";
postdata << "\r\n" << data << "\r\n";
return *this;
}
HttpRequest& HttpRequest::UrlVar(const char *id, const String& data)
{
int c = *path.Last();
@ -481,6 +500,8 @@ void HttpRequest::StartRequest()
}
data << " HTTP/1.1\r\n";
String pd = postdata;
if(!IsNull(multipart))
pd << "--" << multipart << "--\r\n";
if(method == METHOD_GET || method == METHOD_HEAD)
pd.Clear();
if(std_headers) {
@ -521,7 +542,8 @@ void HttpRequest::StartRequest()
else
if(!force_digest && (!IsNull(username) || !IsNull(password)))
data << "Authorization: Basic " << Base64Encode(username + ":" + password) << "\r\n";
data << request_headers << "\r\n" << pd;
data << request_headers;
data << "\r\n" << pd;
LLOG("HTTP REQUEST " << host << ":" << port);
LLOG("HTTP request:\n" << data);
}
@ -717,7 +739,6 @@ void HttpRequest::Finish()
}
if(status_code >= 300 && status_code < 400) {
String url = GetRedirectUrl();
GET();
if(url.GetCount() && redirect_count++ < max_redirects) {
LLOG("--- HTTP redirect " << url);
Url(url);
@ -752,6 +773,8 @@ String HttpRequest::GetPhaseName() const
"Receiving chunk header",
"Receiving content chunk",
"Receiving trailer",
"Request with continue",
"Waiting for continue header",
"Finished",
"Failed",
};

View file

@ -346,6 +346,7 @@ class HttpRequest : public TcpSocket {
String digest;
String request_headers;
String postdata;
String multipart;
VectorMap<String, HttpCookie> cookies;
String protocol;
@ -435,13 +436,15 @@ public:
HttpRequest& PostUData(const String& pd) { return PostData(UrlEncode(pd)); }
HttpRequest& Post(const String& data) { POST(); return PostData(data); }
HttpRequest& Post(const char *id, const String& data);
HttpRequest& ClearPost() { PostData(Null); GET(); return *this; }
HttpRequest& Part(const char *id, const String& data,
const char *content_type = NULL, const char *filename = NULL);
HttpRequest& ClearPost() { PostData(Null); multipart.Clear(); GET(); return *this; }
HttpRequest& Headers(const String& h) { request_headers = h; return *this; }
HttpRequest& ClearHeaders() { return Headers(Null); }
HttpRequest& AddHeaders(const String& h) { request_headers.Cat(h); return *this; }
HttpRequest& Header(const char *id, const String& data);
HttpRequest& Cookie(const HttpCookie& c);
HttpRequest& Cookie(const String& id, const String& value,
const String& domain = Null, const String& path = Null);
@ -487,7 +490,7 @@ public:
SSLPROXYREQUEST, SSLPROXYRESPONSE, SSLHANDSHAKE,
REQUEST, HEADER, BODY,
CHUNK_HEADER, CHUNK_BODY, TRAILER,
FINISHED, FAILED
FINISHED, FAILED,
};
bool Do();

View file

@ -202,6 +202,19 @@ ing][@(0.0.255) `&]_[*@3 data])&]
the format used by HTML forms with `"POST`" method. Returns `*this.&]
[s3;%% &]
[s4; &]
[s5;:HttpRequest`:`:Part`(const char`*`,const String`&`,const char`*`,const char`*`): [_^HttpRequest^ H
ttpRequest][@(0.0.255) `&]_[* Part]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id],
[@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 data], [@(0.0.255) const]_[@(0.0.255) c
har]_`*[*@3 content`_type]_`=_NULL, [@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 filename]_
`=_NULL)&]
[s2;%% First call sets HttpRequest to the multipart mode; unique
part boundary is generated automatically. [%-*@3 id] is name of
the part, [%-*@3 data] is cotnet. If [%-*@3 content`_type] is not
NULL nor empty, it defines `"Content`-Type`" part header. [%-*@3 filename]
can be used to define the `"filename`" part of `"Content`-Disposition`"
part header.&]
[s3;%% &]
[s4; &]
[s5;:HttpRequest`:`:ClearPost`(`): [_^HttpRequest^ HttpRequest][@(0.0.255) `&]_[* ClearPost
]()&]
[s2;%% Empties all Post data and sets the method to GET.&]

View file

@ -22,7 +22,7 @@ XftFont *CreateXftFont(Font font, int angle)
String face = font.GetFaceName();
FcPattern *p = FcPatternCreate();
FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
FcPatternAddBool(p, FC_MINSPACE, 1);

View file

@ -42,7 +42,7 @@ FcPattern *CreateFcPattern(Font font)
String face = font.GetFaceName();
FcPattern *p = FcPatternCreate();
FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
FcPatternAddBool(p, FC_MINSPACE, 1);

View file

@ -370,4 +370,4 @@ Http& Http::UxRun(const String& js_code)
return Ux("!", js_code);
}
};
};