|
|
| version 1.74, 2024/11/04 03:53:25 | version 1.79, 2026/07/13 21:42:16 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b curl parser class. | Parser: @b curl parser class. |
| Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com) |
| Authors: Konstantin Morshnev <moko@design.ru> | Authors: Konstantin Morshnev <moko@design.ru> |
| */ | */ |
| Line 45 typedef void (*t_curl_formfree)(struct c | Line 45 typedef void (*t_curl_formfree)(struct c |
| #define GLINK(name) f_##name=(t_##name)lt_dlsym(handle, #name); | #define GLINK(name) f_##name=(t_##name)lt_dlsym(handle, #name); |
| #define DLINK(name) GLINK(name) if(!f_##name) return "function " #name " was not found"; | #define DLINK(name) GLINK(name) if(!f_##name) return "function " #name " was not found"; |
| static const char *dlink(const char *dlopen_file_spec) { | static const char *dlink(char *dlopen_file_spec) { |
| pa_dlinit(); | pa_dlinit(); |
| lt_dlhandle handle=lt_dlopen(dlopen_file_spec); | lt_dlhandle handle; |
| do { | |
| char *next=lsplit(dlopen_file_spec, ','); | |
| handle=lt_dlopen(dlopen_file_spec); | |
| dlopen_file_spec=next; | |
| } while (!handle && dlopen_file_spec); | |
| if(!handle){ | if(!handle){ |
| if(const char* result=lt_dlerror()) | if(const char* result=lt_dlerror()) |
| Line 136 public: | Line 141 public: |
| } | } |
| }; | }; |
| #ifdef WIN32 | |
| #define CURL_LIBRARY "libcurl" LT_MODULE_EXT | |
| #else | |
| #define CURL_LIBRARY "libcurl" LT_MODULE_EXT ",libcurl" LT_MODULE_EXT ".4" | |
| #endif | |
| bool curl_linked = false; | bool curl_linked = false; |
| const char *curl_status = 0; | const char *curl_status = 0; |
| const char *curl_library="libcurl" LT_MODULE_EXT; | |
| const char *curl_library=CURL_LIBRARY; | |
| static void temp_curl(void (*action)(Request&, MethodParams&), Request& r, MethodParams& params){ | static void temp_curl(void (*action)(Request&, MethodParams&), Request& r, MethodParams& params){ |
| if(!curl_linked) | if(!curl_linked) |
| curl_status=dlink(curl_library); | curl_status=dlink(pa_strdup(curl_library)); |
| if(curl_status == 0){ | if(curl_status == 0){ |
| curl_linked=true; | curl_linked=true; |
| Temp_curl temp_curl; | Temp_curl temp_curl; |
| action(r,params); | action(r,params); |
| } else { | } else { |
| const char *hint=strcmp(curl_library, "libcurl" LT_MODULE_EXT) ? "" : " (at first call ^curl:options[ $.library[correct.libcurl" LT_MODULE_EXT ".name] ])"; | const char *hint=strcmp(curl_library, CURL_LIBRARY) ? "" : " (before use, call ^curl:options[ $.library[correct.libcurl" LT_MODULE_EXT ".name] ])"; |
| throw Exception("curl", 0, "failed to load curl library %s%s", curl_status, hint); | throw Exception("curl", 0, "failed to load curl library %s%s", curl_status, hint); |
| } | } |
| } | } |
| Line 164 static void _curl_session(Request& r, Me | Line 176 static void _curl_session(Request& r, Me |
| } | } |
| static void _curl_version_action(Request& r, MethodParams& ){ | static void _curl_version_action(Request& r, MethodParams& ){ |
| r.write(*new VString(*new String(f_curl_version(), String::L_TAINTED))); | r.write(*new VString(f_curl_version())); |
| } | } |
| static void _curl_version(Request& r, MethodParams& params){ | static void _curl_version(Request& r, MethodParams& params){ |
| Line 554 static void curl_setopt(HashStringValue: | Line 566 static void curl_setopt(HashStringValue: |
| // 'library' parser option | // 'library' parser option |
| if(!curl_linked){ | if(!curl_linked){ |
| curl_library=v.as_string().taint_cstr(String::L_FILE_SPEC); | curl_library=v.as_string().taint_cstr(String::L_FILE_SPEC); |
| if(!curl_library[0]) | |
| curl_library=CURL_LIBRARY; | |
| } else | } else |
| throw Exception("curl", 0, "failed to set option '%s': already loaded", key.cstr()); | throw Exception("curl", 0, "failed to set option '%s': already loaded", key.cstr()); |
| break; | break; |
| Line 630 static Value *curl_getinfo(const String: | Line 644 static Value *curl_getinfo(const String: |
| case CurlInfo::CURL_HTTP_VERSION:{ | case CurlInfo::CURL_HTTP_VERSION:{ |
| long l=0; | long l=0; |
| CURL_GETINFO(l); | CURL_GETINFO(l); |
| return new VString(*new String(curl_http_version_name(l), String::L_TAINTED)); | return new VString(curl_http_version_name(l)); |
| } | } |
| } | } |
| return VVoid::get(); | return VVoid::get(); |
| Line 725 static void _curl_load_action(Request& r | Line 739 static void _curl_load_action(Request& r |
| CURL_SETOPT(CURLOPT_WRITEFUNCTION, curl_writer, "curl writer function"); | CURL_SETOPT(CURLOPT_WRITEFUNCTION, curl_writer, "curl writer function"); |
| CURL_SETOPT(CURLOPT_WRITEDATA, &body, "curl write buffer"); | CURL_SETOPT(CURLOPT_WRITEDATA, &body, "curl write buffer"); |
| char error[CURL_ERROR_SIZE+1]=""; | |
| CURL_SETOPT(CURLOPT_ERRORBUFFER, error, "curl error buffer"); | |
| if(options().is_post && !options().has_content_length){ | if(options().is_post && !options().has_content_length){ |
| // libcurl bug walkaround. Prior to 7.38 (Debian Jessie) curl passed Content-length: -1 | // libcurl bug walkaround. Prior to 7.38 (Debian Jessie) curl passed Content-length: -1 |
| // after that no Content-length header is passed, that hangs request to nginx. | // after that no Content-length header is passed, that hangs request to nginx. |
| Line 753 static void _curl_load_action(Request& r | Line 770 static void _curl_load_action(Request& r |
| check_file_size(response.content_length, new String(options().url)); break; | check_file_size(response.content_length, new String(options().url)); break; |
| default: break; | default: break; |
| } | } |
| throw Exception( PA_DEFAULT(ex_type, "curl.fail"), new String(options().url), "%s", f_curl_easy_strerror(res)); | throw Exception( PA_DEFAULT(ex_type, "curl.fail"), new String(options().url), "%s", error[0] ? error : f_curl_easy_strerror(res)); |
| } | } |
| // assure trailing zero | // assure trailing zero |
| Line 784 static void _curl_load_action(Request& r | Line 801 static void _curl_load_action(Request& r |
| long http_status = 0; | long http_status = 0; |
| if(f_curl_easy_getinfo(curl(), CURLINFO_RESPONSE_CODE, &http_status) == CURLE_OK){ | if(f_curl_easy_getinfo(curl(), CURLINFO_RESPONSE_CODE, &http_status) == CURLE_OK){ |
| result.fields().put("status", new VInt(http_status)); | HASH_PUT_CSTR(result.fields(), "status", new VInt(http_status)); |
| } | } |
| VHash* vtables=new VHash; | VHash* vtables=new VHash; |
| result.fields().put("tables", vtables); | HASH_PUT_CSTR(result.fields(), "tables", vtables); |
| for(Array_iterator<HTTP_Headers::Header> i(response.headers); i; ){ | for(Array_iterator<HTTP_Headers::Header> i(response.headers); i; ){ |
| HTTP_Headers::Header header=i.next(); | HTTP_Headers::Header header=i.next(); |
| Line 804 static void _curl_load_action(Request& r | Line 821 static void _curl_load_action(Request& r |
| // filling $.cookies | // filling $.cookies |
| if(Value *vcookies=vtables->hash().get("SET-COOKIE")) | if(Value *vcookies=vtables->hash().get("SET-COOKIE")) |
| result.fields().put(HTTP_COOKIES_NAME, new VTable(parse_cookies(r, vcookies->get_table()))); | HASH_PUT_CSTR(result.fields(), HTTP_COOKIES_NAME, new VTable(parse_cookies(r, vcookies->get_table()))); |
| r.write(result); | r.write(result); |
| } | } |