#pragma once #include "exthttpcodes.h" #include #include #include #include #include #include #include #include #include #include #include // This is ugly solution but here a lot of work to do it the right way. #define FETCHER_URL_MAX 8192 extern const i64 DEFAULT_RETRY_AFTER; /// == -1 extern const i64 DEFAULT_IF_MODIFIED_SINCE; /// == -1 extern const i32 DEFAULT_MAX_AGE; /// == -1 extern const i8 DEFAULT_REQUEST_PRIORITY; /// == -1 extern const i32 DEFAULT_RESPONSE_TIMEOUT; /// == -1 #define HTTP_PREFIX "http://" #define MAX_LANGREGION_LEN 4 #define MAXWORD_LEN 55 enum HTTP_COMPRESSION { HTTP_COMPRESSION_UNSET = 0, HTTP_COMPRESSION_ERROR = 1, HTTP_COMPRESSION_IDENTITY = 2, HTTP_COMPRESSION_GZIP = 3, HTTP_COMPRESSION_DEFLATE = 4, HTTP_COMPRESSION_COMPRESS = 5, HTTP_COMPRESSION_MAX = 6 }; enum HTTP_METHOD { HTTP_METHOD_UNDEFINED = -1, HTTP_METHOD_OPTIONS, HTTP_METHOD_GET, HTTP_METHOD_HEAD, HTTP_METHOD_POST, HTTP_METHOD_PUT, HTTP_METHOD_DELETE, HTTP_METHOD_TRACE, HTTP_METHOD_CONNECT, HTTP_METHOD_EXTENSION }; enum HTTP_CONNECTION { HTTP_CONNECTION_UNDEFINED = -1, HTTP_CONNECTION_KEEP_ALIVE = 0, HTTP_CONNECTION_CLOSE = 1 }; /// Class represents general http header fields. struct THttpBaseHeader { public: i16 error; i32 header_size; i32 entity_size; i64 content_length; i64 http_time; // seconds since epoch i64 content_range_start; // Content-Range: first-byte-pos i64 content_range_end; // Content-Range: last-byte-pos i64 content_range_entity_length; // Content-Range: entity-length i8 http_minor; i8 mime_type; i8 charset; i8 compression_method; i8 transfer_chunked; i8 connection_closed; TString base; public: void Init() { error = 0; header_size = 0; entity_size = 0; content_length = -1; http_time = -1; http_minor = -1; mime_type = -1; charset = -1; compression_method = HTTP_COMPRESSION_UNSET; transfer_chunked = -1; connection_closed = HTTP_CONNECTION_UNDEFINED; content_range_start = -1; content_range_end = -1; content_range_entity_length = -1; base.clear(); } void Print() const { printf("content_length: %" PRIi64 "\n", content_length); printf("http_time: %" PRIi64 "\n", http_time); printf("http_minor: %" PRIi8 "\n", http_minor); printf("mime_type: %" PRIi8 "\n", mime_type); printf("charset: %" PRIi8 "\n", charset); printf("compression_method: %" PRIi8 "\n", compression_method); printf("transfer_chunked: %" PRIi8 "\n", transfer_chunked); printf("connection_closed: %" PRIi8 "\n", connection_closed); printf("content_range_start: %" PRIi64 "\n", content_range_start); printf("content_range_end: %" PRIi64 "\n", content_range_end); printf("content_range_entity_length: %" PRIi64 "\n", content_range_entity_length); printf("base: \"%s\"\n", base.c_str()); printf("error: %" PRIi16 "\n", error); } int SetBase(const char* path, const char* hostNamePtr = nullptr, int hostNameLength = 0) { if (*path == '/') { base = "http://"; base += TStringBuf(hostNamePtr, hostNameLength); base += path; } else { base = path; } return error; } }; enum { HREFLANG_MAX = FETCHER_URL_MAX * 2 }; /// Class represents Http Response Header. struct THttpHeader: public THttpBaseHeader { public: i8 accept_ranges; i8 squid_error; i8 x_robots_tag; // deprecated, use x_robots_state instead i16 http_status; TString location; TString rel_canonical; char hreflangs[HREFLANG_MAX]; i64 retry_after; TString x_robots_state; // 'xxxxx' format, see `library/html/zoneconf/parsefunc.cpp` public: void Init() { THttpBaseHeader::Init(); accept_ranges = -1; squid_error = 0; x_robots_tag = 0; rel_canonical.clear(); http_status = -1; location.clear(); hreflangs[0] = 0; retry_after = DEFAULT_RETRY_AFTER; x_robots_state = "xxxxx"; } void Print() const { THttpBaseHeader::Print(); printf("http_status: %" PRIi16 "\n", http_status); printf("squid_error: %" PRIi8 "\n", squid_error); printf("accept_ranges: %" PRIi8 "\n", accept_ranges); printf("location: \"%s\"\n", location.c_str()); printf("retry_after: %" PRIi64 "\n", retry_after); } }; struct THttpRequestHeader: public THttpBaseHeader { public: TString request_uri; char host[HOST_MAX]; char from[MAXWORD_LEN]; char user_agent[MAXWORD_LEN]; char x_yandex_langregion[MAX_LANGREGION_LEN]; char x_yandex_sourcename[MAXWORD_LEN]; char x_yandex_requesttype[MAXWORD_LEN]; char x_yandex_fetchoptions[MAXWORD_LEN]; i8 http_method; i8 x_yandex_request_priority; i32 x_yandex_response_timeout; i32 max_age; i64 if_modified_since; public: THttpRequestHeader() { Init(); } void Init() { request_uri.clear(); host[0] = 0; from[0] = 0; user_agent[0] = 0; x_yandex_langregion[0] = 0; x_yandex_sourcename[0] = 0; x_yandex_requesttype[0] = 0; x_yandex_fetchoptions[0] = 0; http_method = HTTP_METHOD_UNDEFINED; x_yandex_request_priority = DEFAULT_REQUEST_PRIORITY; x_yandex_response_timeout = DEFAULT_RESPONSE_TIMEOUT; max_age = DEFAULT_MAX_AGE; if_modified_since = DEFAULT_IF_MODIFIED_SINCE; THttpBaseHeader::Init(); } void Print() const { THttpBaseHeader::Print(); printf("request_uri: \"%s\"\n", request_uri.c_str()); printf("host: \"%s\"\n", host); printf("from: \"%s\"\n", from); printf("user_agent: \"%s\"\n", user_agent); printf("http_method: %" PRIi8 "\n", http_method); printf("response_timeout: %" PRIi32 "\n", x_yandex_response_timeout); printf("max_age: %" PRIi32 "\n", max_age); printf("if_modified_since: %" PRIi64 "\n", if_modified_since); } /// It doesn't care about errors in request or headers, where /// request_uri equals to '*'. /// This returns copy of the string, which you have to delete. TString GetUrl() { TString url; if (host[0] == 0 || !strcmp(host, "")) { url = request_uri; } else { url = HTTP_PREFIX; url += host; url += request_uri; } return url; } char* GetUrl(char* buffer, size_t size) { if (host[0] == 0 || !strcmp(host, "")) { strlcpy(buffer, request_uri.c_str(), size); } else { snprintf(buffer, size, "http://%s%s", host, request_uri.c_str()); } return buffer; } }; class THttpAuthHeader: public THttpHeader { public: char* realm; char* nonce; char* opaque; bool stale; int algorithm; bool qop_auth; bool use_auth; //we do not provide auth-int variant as too heavy //bool qop_auth_int; THttpAuthHeader() : realm(nullptr) , nonce(nullptr) , opaque(nullptr) , stale(false) , algorithm(0) , qop_auth(false) , use_auth(true) { THttpHeader::Init(); } ~THttpAuthHeader() { free(realm); free(nonce); free(opaque); } void Print() { THttpHeader::Print(); if (use_auth) { if (realm) printf("realm: \"%s\"\n", realm); if (nonce) printf("nonce: \"%s\"\n", nonce); if (opaque) printf("opaque: \"%s\"\n", opaque); printf("stale: %d\n", stale); printf("algorithm: %d\n", algorithm); printf("qop_auth: %d\n", qop_auth); } } };