|
|
| version 1.60, 2014/04/15 21:52:57 | version 1.69, 2015/10/26 01:21:58 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: http support functions. | Parser: http support functions. |
| Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 68 static bool set_addr(struct sockaddr_in | Line 68 static bool set_addr(struct sockaddr_in |
| addr->sin_family=AF_INET; | addr->sin_family=AF_INET; |
| addr->sin_port=htons(port); | addr->sin_port=htons(port); |
| if(host) { | if(host) { |
| ulong packed_ip=inet_addr(host); | struct hostent *hostIP=gethostbyname(host); |
| if(packed_ip!=INADDR_NONE) | if(hostIP && hostIP->h_addrtype == AF_INET){ |
| memcpy(&addr->sin_addr, &packed_ip, sizeof(packed_ip)); | memcpy(&addr->sin_addr, hostIP->h_addr, hostIP->h_length); |
| else { | return true; |
| struct hostent *hostIP=gethostbyname(host); | } |
| if(hostIP) | } |
| memcpy(&addr->sin_addr, hostIP->h_addr, hostIP->h_length); | return false; |
| else | |
| return false; | |
| } | |
| } else | |
| addr->sin_addr.s_addr=INADDR_ANY; | |
| return true; | |
| } | } |
| size_t guess_content_length(char* buf) { | size_t guess_content_length(char* buf) { |
| Line 347 static void http_pass_header(HashStringV | Line 341 static void http_pass_header(HashStringV |
| *info->user_agent_specified=true; | *info->user_agent_specified=true; |
| if(strcasecmp(name_cstr, HTTP_CONTENT_TYPE)==0){ | if(strcasecmp(name_cstr, HTTP_CONTENT_TYPE)==0){ |
| *info->content_type_specified=true; | *info->content_type_specified=true; |
| *info->content_type_url_encoded=StrStartFromNC(value.cstr(), HTTP_CONTENT_TYPE_FORM_URLENCODED); | *info->content_type_url_encoded=pa_strncasecmp(value.cstr(), HTTP_CONTENT_TYPE_FORM_URLENCODED)==0; |
| } | } |
| } | } |
| Line 410 static void form_value2string( | Line 404 static void form_value2string( |
| } else | } else |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| new String(key, String::L_TAINTED), | new String(key, String::L_TAINTED), |
| "is %s, "HTTP_FORM_NAME" option value can be string or table only (file is allowed for $."HTTP_METHOD_NAME"[POST] + $."HTTP_FORM_ENCTYPE_NAME"["HTTP_CONTENT_TYPE_MULTIPART_FORMDATA"])", value->type()); | "is %s, " HTTP_FORM_NAME " option value can be string or table only (file is allowed for $." HTTP_METHOD_NAME "[POST] + $." HTTP_FORM_ENCTYPE_NAME "[" HTTP_CONTENT_TYPE_MULTIPART_FORMDATA "])", value->type()); |
| } | } |
| const char* pa_form2string(HashStringValue& form, Request_charsets& charsets) { | const char* pa_form2string(HashStringValue& form, Request_charsets& charsets) { |
| Line 516 static void form_value2part( | Line 510 static void form_value2part( |
| } else | } else |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| new String(key, String::L_TAINTED), | new String(key, String::L_TAINTED), |
| "is %s, "HTTP_FORM_NAME" option value can be string, table or file only", value->type()); | "is %s, " HTTP_FORM_NAME " option value can be string, table or file only", value->type()); |
| } | } |
| const char* pa_form2string_multipart(HashStringValue& form, Request& r, const char* boundary, size_t& post_size){ | const char* pa_form2string_multipart(HashStringValue& form, Request& r, const char* boundary, size_t& post_size){ |
| Line 548 static void find_headers_end(char* p, | Line 542 static void find_headers_end(char* p, |
| // Set-Cookie: name=value; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly | // Set-Cookie: name=value; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly |
| static ArrayString* parse_cookie(Request& r, const String& cookie) { | static ArrayString* parse_cookie(Request& r, const String& cookie) { |
| char *current=strdup(cookie.cstr()); | char *current=pa_strdup(cookie.cstr()); |
| const String* name=0; | const String* name=0; |
| const String* value=&String::Empty; | const String* value=&String::Empty; |
| Line 630 File_read_http_result pa_internal_file_r | Line 624 File_read_http_result pa_internal_file_r |
| bool transcode_text_result) { | bool transcode_text_result) { |
| File_read_http_result result; | File_read_http_result result; |
| char host[MAX_STRING]; | char host[MAX_STRING]; |
| const char *idna_host; | |
| const char* uri; | const char* uri; |
| short port=80; | short port=80; |
| const char* method="GET"; | const char* method="GET"; |
| Line 686 File_read_http_result pa_internal_file_r | Line 681 File_read_http_result pa_internal_file_r |
| omit_post_charset=vomit_post_charset->as_bool(); | omit_post_charset=vomit_post_charset->as_bool(); |
| } | } |
| if(Value* vcharset_name=options->get(PA_CHARSET_NAME)) { | if(Value* vcharset_name=options->get(PA_CHARSET_NAME)) { |
| valid_options++; | |
| asked_remote_charset=&charsets.get(vcharset_name->as_string().change_case(r.charsets.source(), String::CC_UPPER)); | asked_remote_charset=&charsets.get(vcharset_name->as_string().change_case(r.charsets.source(), String::CC_UPPER)); |
| } | } |
| if(Value* vresponse_charset_name=options->get(PA_RESPONSE_CHARSET_NAME)) { | if(Value* vresponse_charset_name=options->get(PA_RESPONSE_CHARSET_NAME)) { |
| valid_options++; | |
| real_remote_charset=&charsets.get(vresponse_charset_name->as_string().change_case(r.charsets.source(), String::CC_UPPER)); | real_remote_charset=&charsets.get(vresponse_charset_name->as_string().change_case(r.charsets.source(), String::CC_UPPER)); |
| } | } |
| if(Value* vuser=options->get(HTTP_USER)) { | if(Value* vuser=options->get(HTTP_USER)) { |
| Line 711 File_read_http_result pa_internal_file_r | Line 706 File_read_http_result pa_internal_file_r |
| if(method_is_get) | if(method_is_get) |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "you can not use $."HTTP_FORM_ENCTYPE_NAME" option with method GET"); | "you can not use $." HTTP_FORM_ENCTYPE_NAME " option with method GET"); |
| multipart=strcasecmp(encode, HTTP_CONTENT_TYPE_MULTIPART_FORMDATA)==0; | multipart=strcasecmp(encode, HTTP_CONTENT_TYPE_MULTIPART_FORMDATA)==0; |
| if(!multipart && strcasecmp(encode, HTTP_CONTENT_TYPE_FORM_URLENCODED)!=0) | if(!multipart && strcasecmp(encode, HTTP_CONTENT_TYPE_FORM_URLENCODED)!=0) |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "$."HTTP_FORM_ENCTYPE_NAME" option value can be "HTTP_CONTENT_TYPE_FORM_URLENCODED" or "HTTP_CONTENT_TYPE_MULTIPART_FORMDATA" only"); | "$." HTTP_FORM_ENCTYPE_NAME " option value can be " HTTP_CONTENT_TYPE_FORM_URLENCODED " or " HTTP_CONTENT_TYPE_MULTIPART_FORMDATA " only"); |
| } | } |
| if(vbody){ | if(vbody){ |
| if(method_is_get) | if(method_is_get) |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "you can not use $."HTTP_BODY_NAME" option with method GET"); | "you can not use $." HTTP_BODY_NAME " option with method GET"); |
| if(form) | if(form) |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "you can not use options $."HTTP_BODY_NAME" and $."HTTP_FORM_NAME" together"); | "you can not use options $." HTTP_BODY_NAME " and $." HTTP_FORM_NAME " together"); |
| } | } |
| //preparing request | //preparing request |
| Line 763 File_read_http_result pa_internal_file_r | Line 758 File_read_http_result pa_internal_file_r |
| throw Exception(PARSER_RUNTIME, &connect_string, "invalid port number '%s'", port_cstr); | throw Exception(PARSER_RUNTIME, &connect_string, "invalid port number '%s'", port_cstr); |
| } | } |
| idna_host=pa_idna_encode(host, r.charsets.source()); | |
| // making request head | // making request head |
| String head; | String head; |
| head << method << " " << uri; | head << method << " " << uri; |
| if(method_is_get && form) | if(method_is_get && form) |
| head << (strchr(uri, '?')!=0?"&":"?") << pa_form2string(*form, r.charsets); | head << (strchr(uri, '?')!=0?"&":"?") << pa_form2string(*form, r.charsets); |
| head <<" HTTP/1.0" CRLF "Host: "<< host; | head <<" HTTP/1.0" CRLF "Host: "<< idna_host; |
| if (port != 80) | if (port != 80) |
| head << ":" << port_cstr; | head << ":" << port_cstr; |
| head << CRLF; | head << CRLF; |
| Line 834 File_read_http_result pa_internal_file_r | Line 831 File_read_http_result pa_internal_file_r |
| String::C(vbody->as_string().cstr(), vbody->as_string().length()), | String::C(vbody->as_string().cstr(), vbody->as_string().length()), |
| r.charsets.source(), | r.charsets.source(), |
| *asked_remote_charset | *asked_remote_charset |
| ); | ).str; |
| } | } |
| post_size=strlen(request_body); | post_size=strlen(request_body); |
| } | } |
| Line 890 File_read_http_result pa_internal_file_r | Line 887 File_read_http_result pa_internal_file_r |
| // sending request | // sending request |
| int status_code=http_request(response, response_size, | int status_code=http_request(response, response_size, |
| host, port, request, request_size, | idna_host, port, request, request_size, |
| timeout_secs, fail_on_status_ne_200); | timeout_secs, fail_on_status_ne_200); |
| // processing results | // processing results |
| Line 960 File_read_http_result pa_internal_file_r | Line 957 File_read_http_result pa_internal_file_r |
| result.headers->put(HTTP_COOKIES_NAME, new VTable(parse_cookies(r, vcookies->get_table()))); | result.headers->put(HTTP_COOKIES_NAME, new VTable(parse_cookies(r, vcookies->get_table()))); |
| } | } |
| if(as_text && raw_body_size>=3 && strncmp(raw_body, "\xEF\xBB\xBF", 3)==0){ | if(as_text){ |
| // skip UTF-8 signature (BOM code) | real_remote_charset=charsets.checkBOM(raw_body, raw_body_size, real_remote_charset); |
| raw_body+=3; | |
| raw_body_size-=3; | |
| if(!real_remote_charset) | |
| real_remote_charset=&UTF8_charset; | |
| } | } |
| // output response | // output response |