diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:17 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:17 +0300 |
commit | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (patch) | |
tree | dd4bd3ca0f36b817e96812825ffaf10d645803f2 /library/cpp/http | |
parent | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (diff) | |
download | ydb-d3a398281c6fd1d3672036cb2d63f842d2cb28c5.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/http')
63 files changed, 3773 insertions, 3773 deletions
diff --git a/library/cpp/http/fetch/exthttpcodes.cpp b/library/cpp/http/fetch/exthttpcodes.cpp index baa2a2a0fd..acc05650c8 100644 --- a/library/cpp/http/fetch/exthttpcodes.cpp +++ b/library/cpp/http/fetch/exthttpcodes.cpp @@ -1,160 +1,160 @@ -#include "exthttpcodes.h" - +#include "exthttpcodes.h" + #include <cstring> -const ui16 CrazyServer = ShouldDelete | MarkSuspect; +const ui16 CrazyServer = ShouldDelete | MarkSuspect; -struct http_flag { - ui16 http; - ui16 flag; -}; +struct http_flag { + ui16 http; + ui16 flag; +}; static http_flag HTTP_FLAG[] = { - {HTTP_CONTINUE, MarkSuspect}, // 100 - {HTTP_SWITCHING_PROTOCOLS, CrazyServer}, // 101 - {HTTP_PROCESSING, CrazyServer}, // 102 + {HTTP_CONTINUE, MarkSuspect}, // 100 + {HTTP_SWITCHING_PROTOCOLS, CrazyServer}, // 101 + {HTTP_PROCESSING, CrazyServer}, // 102 - {HTTP_OK, ShouldReindex}, // 200 - {HTTP_CREATED, CrazyServer}, // 201 - {HTTP_ACCEPTED, ShouldDelete}, // 202 - {HTTP_NON_AUTHORITATIVE_INFORMATION, ShouldReindex}, // 203 - {HTTP_NO_CONTENT, ShouldDelete}, // 204 - {HTTP_RESET_CONTENT, ShouldDelete}, // 205 - {HTTP_PARTIAL_CONTENT, ShouldReindex}, // 206 - {HTTP_MULTI_STATUS, CrazyServer}, // 207 - {HTTP_ALREADY_REPORTED, CrazyServer}, // 208 - {HTTP_IM_USED, CrazyServer}, // 226 + {HTTP_OK, ShouldReindex}, // 200 + {HTTP_CREATED, CrazyServer}, // 201 + {HTTP_ACCEPTED, ShouldDelete}, // 202 + {HTTP_NON_AUTHORITATIVE_INFORMATION, ShouldReindex}, // 203 + {HTTP_NO_CONTENT, ShouldDelete}, // 204 + {HTTP_RESET_CONTENT, ShouldDelete}, // 205 + {HTTP_PARTIAL_CONTENT, ShouldReindex}, // 206 + {HTTP_MULTI_STATUS, CrazyServer}, // 207 + {HTTP_ALREADY_REPORTED, CrazyServer}, // 208 + {HTTP_IM_USED, CrazyServer}, // 226 - {HTTP_MULTIPLE_CHOICES, CheckLinks | ShouldDelete}, // 300 - {HTTP_MOVED_PERMANENTLY, CheckLocation | ShouldDelete | MoveRedir}, // 301 - {HTTP_FOUND, CheckLocation | ShouldDelete | MoveRedir}, // 302 - {HTTP_SEE_OTHER, CheckLocation | ShouldDelete | MoveRedir}, // 303 - {HTTP_NOT_MODIFIED, 0}, // 304 - {HTTP_USE_PROXY, ShouldDelete}, // 305 - {HTTP_TEMPORARY_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 307 - {HTTP_PERMANENT_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 308 + {HTTP_MULTIPLE_CHOICES, CheckLinks | ShouldDelete}, // 300 + {HTTP_MOVED_PERMANENTLY, CheckLocation | ShouldDelete | MoveRedir}, // 301 + {HTTP_FOUND, CheckLocation | ShouldDelete | MoveRedir}, // 302 + {HTTP_SEE_OTHER, CheckLocation | ShouldDelete | MoveRedir}, // 303 + {HTTP_NOT_MODIFIED, 0}, // 304 + {HTTP_USE_PROXY, ShouldDelete}, // 305 + {HTTP_TEMPORARY_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 307 + {HTTP_PERMANENT_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 308 - {HTTP_BAD_REQUEST, CrazyServer}, // 400 - {HTTP_UNAUTHORIZED, ShouldDelete}, // 401 - {HTTP_PAYMENT_REQUIRED, ShouldDelete}, // 402 - {HTTP_FORBIDDEN, ShouldDelete}, // 403 - {HTTP_NOT_FOUND, ShouldDelete}, // 404 - {HTTP_METHOD_NOT_ALLOWED, ShouldDelete}, // 405 - {HTTP_NOT_ACCEPTABLE, ShouldDelete}, // 406 - {HTTP_PROXY_AUTHENTICATION_REQUIRED, CrazyServer}, // 407 - {HTTP_REQUEST_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 408 - {HTTP_CONFLICT, MarkSuspect}, // 409 - {HTTP_GONE, ShouldDelete}, // 410 - {HTTP_LENGTH_REQUIRED, CrazyServer}, // 411 - {HTTP_PRECONDITION_FAILED, CrazyServer}, // 412 - {HTTP_REQUEST_ENTITY_TOO_LARGE, CrazyServer}, // 413 - {HTTP_REQUEST_URI_TOO_LARGE, ShouldDelete}, // 414 - {HTTP_UNSUPPORTED_MEDIA_TYPE, CrazyServer}, // 415 - {HTTP_REQUESTED_RANGE_NOT_SATISFIABLE, CrazyServer}, // 416 - {HTTP_EXPECTATION_FAILED, ShouldDelete}, // 417 - {HTTP_I_AM_A_TEAPOT, CrazyServer}, // 418 - {HTTP_AUTHENTICATION_TIMEOUT, ShouldDelete}, // 419 + {HTTP_BAD_REQUEST, CrazyServer}, // 400 + {HTTP_UNAUTHORIZED, ShouldDelete}, // 401 + {HTTP_PAYMENT_REQUIRED, ShouldDelete}, // 402 + {HTTP_FORBIDDEN, ShouldDelete}, // 403 + {HTTP_NOT_FOUND, ShouldDelete}, // 404 + {HTTP_METHOD_NOT_ALLOWED, ShouldDelete}, // 405 + {HTTP_NOT_ACCEPTABLE, ShouldDelete}, // 406 + {HTTP_PROXY_AUTHENTICATION_REQUIRED, CrazyServer}, // 407 + {HTTP_REQUEST_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 408 + {HTTP_CONFLICT, MarkSuspect}, // 409 + {HTTP_GONE, ShouldDelete}, // 410 + {HTTP_LENGTH_REQUIRED, CrazyServer}, // 411 + {HTTP_PRECONDITION_FAILED, CrazyServer}, // 412 + {HTTP_REQUEST_ENTITY_TOO_LARGE, CrazyServer}, // 413 + {HTTP_REQUEST_URI_TOO_LARGE, ShouldDelete}, // 414 + {HTTP_UNSUPPORTED_MEDIA_TYPE, CrazyServer}, // 415 + {HTTP_REQUESTED_RANGE_NOT_SATISFIABLE, CrazyServer}, // 416 + {HTTP_EXPECTATION_FAILED, ShouldDelete}, // 417 + {HTTP_I_AM_A_TEAPOT, CrazyServer}, // 418 + {HTTP_AUTHENTICATION_TIMEOUT, ShouldDelete}, // 419 - {HTTP_MISDIRECTED_REQUEST, CrazyServer}, // 421 - {HTTP_UNPROCESSABLE_ENTITY, CrazyServer}, // 422 - {HTTP_LOCKED, ShouldDelete}, // 423 - {HTTP_FAILED_DEPENDENCY, CrazyServer}, // 424 - {HTTP_UPGRADE_REQUIRED, ShouldDelete}, // 426 - {HTTP_PRECONDITION_REQUIRED, ShouldDelete}, // 428 - {HTTP_TOO_MANY_REQUESTS, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 429 - {HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, ShouldDelete}, // 451 + {HTTP_MISDIRECTED_REQUEST, CrazyServer}, // 421 + {HTTP_UNPROCESSABLE_ENTITY, CrazyServer}, // 422 + {HTTP_LOCKED, ShouldDelete}, // 423 + {HTTP_FAILED_DEPENDENCY, CrazyServer}, // 424 + {HTTP_UPGRADE_REQUIRED, ShouldDelete}, // 426 + {HTTP_PRECONDITION_REQUIRED, ShouldDelete}, // 428 + {HTTP_TOO_MANY_REQUESTS, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 429 + {HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, ShouldDelete}, // 451 - {HTTP_INTERNAL_SERVER_ERROR, MarkSuspect}, // 500 - {HTTP_NOT_IMPLEMENTED, ShouldDelete | ShouldDisconnect}, // 501 - {HTTP_BAD_GATEWAY, MarkSuspect}, // 502 - {HTTP_SERVICE_UNAVAILABLE, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 503 - {HTTP_GATEWAY_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 504 - {HTTP_HTTP_VERSION_NOT_SUPPORTED, CrazyServer | ShouldDisconnect}, // 505 + {HTTP_INTERNAL_SERVER_ERROR, MarkSuspect}, // 500 + {HTTP_NOT_IMPLEMENTED, ShouldDelete | ShouldDisconnect}, // 501 + {HTTP_BAD_GATEWAY, MarkSuspect}, // 502 + {HTTP_SERVICE_UNAVAILABLE, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 503 + {HTTP_GATEWAY_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 504 + {HTTP_HTTP_VERSION_NOT_SUPPORTED, CrazyServer | ShouldDisconnect}, // 505 - {HTTP_VARIANT_ALSO_NEGOTIATES, CrazyServer | ShouldDisconnect}, // 506 - {HTTP_INSUFFICIENT_STORAGE, CrazyServer | ShouldDisconnect}, // 507 - {HTTP_LOOP_DETECTED, CrazyServer | ShouldDisconnect}, // 508 - {HTTP_BANDWIDTH_LIMIT_EXCEEDED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 509 - {HTTP_NOT_EXTENDED, ShouldDelete}, // 510 - {HTTP_NETWORK_AUTHENTICATION_REQUIRED, ShouldDelete}, // 511 + {HTTP_VARIANT_ALSO_NEGOTIATES, CrazyServer | ShouldDisconnect}, // 506 + {HTTP_INSUFFICIENT_STORAGE, CrazyServer | ShouldDisconnect}, // 507 + {HTTP_LOOP_DETECTED, CrazyServer | ShouldDisconnect}, // 508 + {HTTP_BANDWIDTH_LIMIT_EXCEEDED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 509 + {HTTP_NOT_EXTENDED, ShouldDelete}, // 510 + {HTTP_NETWORK_AUTHENTICATION_REQUIRED, ShouldDelete}, // 511 - // custom - {HTTP_BAD_RESPONSE_HEADER, CrazyServer}, // 1000 - {HTTP_CONNECTION_LOST, ShouldRetry}, // 1001 - {HTTP_BODY_TOO_LARGE, ShouldDelete | CanBeFake}, // 1002 - {HTTP_ROBOTS_TXT_DISALLOW, ShouldDelete}, // 1003 - {HTTP_BAD_URL, ShouldDelete}, // 1004 - {HTTP_BAD_MIME, ShouldDelete}, // 1005 - {HTTP_DNS_FAILURE, ShouldDisconnect | MarkSuspect}, // 1006 - {HTTP_BAD_STATUS_CODE, CrazyServer}, // 1007 - {HTTP_BAD_HEADER_STRING, CrazyServer}, // 1008 - {HTTP_BAD_CHUNK, CrazyServer}, // 1009 - {HTTP_CONNECT_FAILED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 1010 - {HTTP_FILTER_DISALLOW, ShouldDelete}, // 1011 - {HTTP_LOCAL_EIO, ShouldRetry}, // 1012 - {HTTP_BAD_CONTENT_LENGTH, ShouldDelete}, // 1013 - {HTTP_BAD_ENCODING, ShouldDelete}, // 1014 - {HTTP_LENGTH_UNKNOWN, ShouldDelete}, // 1015 - {HTTP_HEADER_EOF, ShouldRetry | CanBeFake}, // 1016 - {HTTP_MESSAGE_EOF, ShouldRetry | CanBeFake}, // 1017 - {HTTP_CHUNK_EOF, ShouldRetry | CanBeFake}, // 1018 - {HTTP_PAST_EOF, ShouldRetry | ShouldDelete | CanBeFake}, // 1019 - {HTTP_HEADER_TOO_LARGE, ShouldDelete}, // 1020 - {HTTP_URL_TOO_LARGE, ShouldDelete}, // 1021 - {HTTP_INTERRUPTED, 0}, // 1022 - {HTTP_CUSTOM_NOT_MODIFIED, 0}, // 1023 - {HTTP_BAD_CONTENT_ENCODING, ShouldDelete}, // 1024 - {HTTP_PROXY_UNKNOWN, 0}, // 1030 - {HTTP_PROXY_REQUEST_TIME_OUT, 0}, // 1031 - {HTTP_PROXY_INTERNAL_ERROR, 0}, // 1032 - {HTTP_PROXY_CONNECT_FAILED, 0}, // 1033 - {HTTP_PROXY_CONNECTION_LOST, 0}, // 1034 - {HTTP_PROXY_NO_PROXY, 0}, // 1035 - {HTTP_PROXY_ERROR, 0}, // 1036 - {HTTP_SSL_ERROR, 0}, // 1037 - {HTTP_CACHED_COPY_NOT_FOUND, 0}, // 1038 - {HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING, ShouldRetry}, // 1039 - {HTTP_FETCHER_BAD_RESPONSE, 0}, // 1040 - {HTTP_FETCHER_MB_ERROR, 0}, // 1041 - {HTTP_SSL_CERT_ERROR, 0}, // 1042 + // custom + {HTTP_BAD_RESPONSE_HEADER, CrazyServer}, // 1000 + {HTTP_CONNECTION_LOST, ShouldRetry}, // 1001 + {HTTP_BODY_TOO_LARGE, ShouldDelete | CanBeFake}, // 1002 + {HTTP_ROBOTS_TXT_DISALLOW, ShouldDelete}, // 1003 + {HTTP_BAD_URL, ShouldDelete}, // 1004 + {HTTP_BAD_MIME, ShouldDelete}, // 1005 + {HTTP_DNS_FAILURE, ShouldDisconnect | MarkSuspect}, // 1006 + {HTTP_BAD_STATUS_CODE, CrazyServer}, // 1007 + {HTTP_BAD_HEADER_STRING, CrazyServer}, // 1008 + {HTTP_BAD_CHUNK, CrazyServer}, // 1009 + {HTTP_CONNECT_FAILED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 1010 + {HTTP_FILTER_DISALLOW, ShouldDelete}, // 1011 + {HTTP_LOCAL_EIO, ShouldRetry}, // 1012 + {HTTP_BAD_CONTENT_LENGTH, ShouldDelete}, // 1013 + {HTTP_BAD_ENCODING, ShouldDelete}, // 1014 + {HTTP_LENGTH_UNKNOWN, ShouldDelete}, // 1015 + {HTTP_HEADER_EOF, ShouldRetry | CanBeFake}, // 1016 + {HTTP_MESSAGE_EOF, ShouldRetry | CanBeFake}, // 1017 + {HTTP_CHUNK_EOF, ShouldRetry | CanBeFake}, // 1018 + {HTTP_PAST_EOF, ShouldRetry | ShouldDelete | CanBeFake}, // 1019 + {HTTP_HEADER_TOO_LARGE, ShouldDelete}, // 1020 + {HTTP_URL_TOO_LARGE, ShouldDelete}, // 1021 + {HTTP_INTERRUPTED, 0}, // 1022 + {HTTP_CUSTOM_NOT_MODIFIED, 0}, // 1023 + {HTTP_BAD_CONTENT_ENCODING, ShouldDelete}, // 1024 + {HTTP_PROXY_UNKNOWN, 0}, // 1030 + {HTTP_PROXY_REQUEST_TIME_OUT, 0}, // 1031 + {HTTP_PROXY_INTERNAL_ERROR, 0}, // 1032 + {HTTP_PROXY_CONNECT_FAILED, 0}, // 1033 + {HTTP_PROXY_CONNECTION_LOST, 0}, // 1034 + {HTTP_PROXY_NO_PROXY, 0}, // 1035 + {HTTP_PROXY_ERROR, 0}, // 1036 + {HTTP_SSL_ERROR, 0}, // 1037 + {HTTP_CACHED_COPY_NOT_FOUND, 0}, // 1038 + {HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING, ShouldRetry}, // 1039 + {HTTP_FETCHER_BAD_RESPONSE, 0}, // 1040 + {HTTP_FETCHER_MB_ERROR, 0}, // 1041 + {HTTP_SSL_CERT_ERROR, 0}, // 1042 - // Custom (replace HTTP 200/304) - {EXT_HTTP_MIRRMOVE, 0}, // 2000 - {EXT_HTTP_MANUAL_DELETE, ShouldDelete}, // 2001 - {EXT_HTTP_NOTUSED2, ShouldDelete}, // 2002 - {EXT_HTTP_NOTUSED3, ShouldDelete}, // 2003 - {EXT_HTTP_REFRESH, ShouldDelete | CheckLinks | MoveRedir}, // 2004 - {EXT_HTTP_NOINDEX, ShouldDelete | CheckLinks}, // 2005 - {EXT_HTTP_BADCODES, ShouldDelete}, // 2006 - {EXT_HTTP_SITESTAT, ShouldDelete}, // 2007 - {EXT_HTTP_IOERROR, ShouldDelete}, // 2008 - {EXT_HTTP_BASEERROR, ShouldDelete}, // 2009 - {EXT_HTTP_PARSERROR, ShouldDelete | CanBeFake}, // 2010 - {EXT_HTTP_BAD_CHARSET, ShouldDelete | CheckLinks}, // 2011 - {EXT_HTTP_BAD_LANGUAGE, ShouldDelete | CheckLinks}, // 2012 - {EXT_HTTP_NUMERERROR, ShouldDelete}, // 2013 - {EXT_HTTP_EMPTYDOC, ShouldDelete | CheckLinks}, // 2014 - {EXT_HTTP_HUGEDOC, ShouldDelete}, // 2015 - {EXT_HTTP_LINKGARBAGE, ShouldDelete}, // 2016 - {EXT_HTTP_PARSERFAIL, ShouldDelete}, // 2019 - {EXT_HTTP_GZIPERROR, ShouldDelete}, // 2020 - {EXT_HTTP_MANUAL_DELETE_URL, ShouldDelete}, // 2022 - {EXT_HTTP_CUSTOM_PARTIAL_CONTENT, ShouldReindex}, // 2023 - {EXT_HTTP_EMPTY_RESPONSE, ShouldDelete}, // 2024 - {EXT_HTTP_REL_CANONICAL, ShouldDelete | CheckLinks | MoveRedir}, // 2025 - {0, 0}}; + // Custom (replace HTTP 200/304) + {EXT_HTTP_MIRRMOVE, 0}, // 2000 + {EXT_HTTP_MANUAL_DELETE, ShouldDelete}, // 2001 + {EXT_HTTP_NOTUSED2, ShouldDelete}, // 2002 + {EXT_HTTP_NOTUSED3, ShouldDelete}, // 2003 + {EXT_HTTP_REFRESH, ShouldDelete | CheckLinks | MoveRedir}, // 2004 + {EXT_HTTP_NOINDEX, ShouldDelete | CheckLinks}, // 2005 + {EXT_HTTP_BADCODES, ShouldDelete}, // 2006 + {EXT_HTTP_SITESTAT, ShouldDelete}, // 2007 + {EXT_HTTP_IOERROR, ShouldDelete}, // 2008 + {EXT_HTTP_BASEERROR, ShouldDelete}, // 2009 + {EXT_HTTP_PARSERROR, ShouldDelete | CanBeFake}, // 2010 + {EXT_HTTP_BAD_CHARSET, ShouldDelete | CheckLinks}, // 2011 + {EXT_HTTP_BAD_LANGUAGE, ShouldDelete | CheckLinks}, // 2012 + {EXT_HTTP_NUMERERROR, ShouldDelete}, // 2013 + {EXT_HTTP_EMPTYDOC, ShouldDelete | CheckLinks}, // 2014 + {EXT_HTTP_HUGEDOC, ShouldDelete}, // 2015 + {EXT_HTTP_LINKGARBAGE, ShouldDelete}, // 2016 + {EXT_HTTP_PARSERFAIL, ShouldDelete}, // 2019 + {EXT_HTTP_GZIPERROR, ShouldDelete}, // 2020 + {EXT_HTTP_MANUAL_DELETE_URL, ShouldDelete}, // 2022 + {EXT_HTTP_CUSTOM_PARTIAL_CONTENT, ShouldReindex}, // 2023 + {EXT_HTTP_EMPTY_RESPONSE, ShouldDelete}, // 2024 + {EXT_HTTP_REL_CANONICAL, ShouldDelete | CheckLinks | MoveRedir}, // 2025 + {0, 0}}; -static ui16* prepare_flags(http_flag* arg) { +static ui16* prepare_flags(http_flag* arg) { static ui16 flags[EXT_HTTP_CODE_MAX]; - http_flag* ptr; + http_flag* ptr; size_t i; // устанавливаем значение по умолчанию для кодов не перечисленных в таблице выше - for (i = 0; i < EXT_HTTP_CODE_MAX; ++i) + for (i = 0; i < EXT_HTTP_CODE_MAX; ++i) flags[i] = CrazyServer; // устанавливаем флаги для перечисленных кодов - for (ptr = arg; ptr->http; ++ptr) - flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag; + for (ptr = arg; ptr->http; ++ptr) + flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag; // для стандартных кодов ошибок берем флаги из первого кода каждой группы и проставляем их // всем кодам не перечисленным в таблице выше @@ -164,103 +164,103 @@ static ui16* prepare_flags(http_flag* arg) { // предыдущий цикл затер некоторые флаги перечисленные в таблице выше // восстанавливаем их - for (ptr = arg; ptr->http; ++ptr) - flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag; + for (ptr = arg; ptr->http; ++ptr) + flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag; return flags; } -ui16* http2status = prepare_flags(HTTP_FLAG); +ui16* http2status = prepare_flags(HTTP_FLAG); TStringBuf ExtHttpCodeStr(int code) noexcept { if (code < HTTP_CODE_MAX) { return HttpCodeStr(code); } switch (code) { - case HTTP_BAD_RESPONSE_HEADER: + case HTTP_BAD_RESPONSE_HEADER: return TStringBuf("Bad response header"); - case HTTP_CONNECTION_LOST: + case HTTP_CONNECTION_LOST: return TStringBuf("Connection lost"); - case HTTP_BODY_TOO_LARGE: + case HTTP_BODY_TOO_LARGE: return TStringBuf("Body too large"); - case HTTP_ROBOTS_TXT_DISALLOW: + case HTTP_ROBOTS_TXT_DISALLOW: return TStringBuf("robots.txt disallow"); - case HTTP_BAD_URL: + case HTTP_BAD_URL: return TStringBuf("Bad url"); - case HTTP_BAD_MIME: + case HTTP_BAD_MIME: return TStringBuf("Bad mime type"); - case HTTP_DNS_FAILURE: + case HTTP_DNS_FAILURE: return TStringBuf("Dns failure"); - case HTTP_BAD_STATUS_CODE: + case HTTP_BAD_STATUS_CODE: return TStringBuf("Bad status code"); - case HTTP_BAD_HEADER_STRING: + case HTTP_BAD_HEADER_STRING: return TStringBuf("Bad header string"); - case HTTP_BAD_CHUNK: + case HTTP_BAD_CHUNK: return TStringBuf("Bad chunk"); - case HTTP_CONNECT_FAILED: + case HTTP_CONNECT_FAILED: return TStringBuf("Connect failed"); - case HTTP_FILTER_DISALLOW: + case HTTP_FILTER_DISALLOW: return TStringBuf("Filter disallow"); - case HTTP_LOCAL_EIO: + case HTTP_LOCAL_EIO: return TStringBuf("Local eio"); - case HTTP_BAD_CONTENT_LENGTH: + case HTTP_BAD_CONTENT_LENGTH: return TStringBuf("Bad content length"); - case HTTP_BAD_ENCODING: + case HTTP_BAD_ENCODING: return TStringBuf("Bad encoding"); - case HTTP_LENGTH_UNKNOWN: + case HTTP_LENGTH_UNKNOWN: return TStringBuf("Length unknown"); - case HTTP_HEADER_EOF: + case HTTP_HEADER_EOF: return TStringBuf("Header EOF"); - case HTTP_MESSAGE_EOF: + case HTTP_MESSAGE_EOF: return TStringBuf("Message EOF"); - case HTTP_CHUNK_EOF: + case HTTP_CHUNK_EOF: return TStringBuf("Chunk EOF"); - case HTTP_PAST_EOF: + case HTTP_PAST_EOF: return TStringBuf("Past EOF"); - case HTTP_HEADER_TOO_LARGE: + case HTTP_HEADER_TOO_LARGE: return TStringBuf("Header is too large"); - case HTTP_URL_TOO_LARGE: + case HTTP_URL_TOO_LARGE: return TStringBuf("Url is too large"); - case HTTP_INTERRUPTED: + case HTTP_INTERRUPTED: return TStringBuf("Interrupted"); - case HTTP_CUSTOM_NOT_MODIFIED: + case HTTP_CUSTOM_NOT_MODIFIED: return TStringBuf("Signature detector thinks that doc is not modified"); - case HTTP_BAD_CONTENT_ENCODING: + case HTTP_BAD_CONTENT_ENCODING: return TStringBuf("Bad content encoding"); - case HTTP_NO_RESOURCES: + case HTTP_NO_RESOURCES: return TStringBuf("No resources"); - case HTTP_FETCHER_SHUTDOWN: + case HTTP_FETCHER_SHUTDOWN: return TStringBuf("Fetcher shutdown"); - case HTTP_CHUNK_TOO_LARGE: + case HTTP_CHUNK_TOO_LARGE: return TStringBuf("Chunk size is too big"); - case HTTP_SERVER_BUSY: + case HTTP_SERVER_BUSY: return TStringBuf("Server is busy"); - case HTTP_SERVICE_UNKNOWN: + case HTTP_SERVICE_UNKNOWN: return TStringBuf("Service is unknown"); - case HTTP_PROXY_UNKNOWN: + case HTTP_PROXY_UNKNOWN: return TStringBuf("Zora: unknown error"); - case HTTP_PROXY_REQUEST_TIME_OUT: + case HTTP_PROXY_REQUEST_TIME_OUT: return TStringBuf("Zora: request time out"); - case HTTP_PROXY_INTERNAL_ERROR: + case HTTP_PROXY_INTERNAL_ERROR: return TStringBuf("Zora: internal server error"); - case HTTP_PROXY_CONNECT_FAILED: + case HTTP_PROXY_CONNECT_FAILED: return TStringBuf("Spider proxy connect failed"); - case HTTP_PROXY_CONNECTION_LOST: + case HTTP_PROXY_CONNECTION_LOST: return TStringBuf("Spider proxy connection lost"); - case HTTP_PROXY_NO_PROXY: + case HTTP_PROXY_NO_PROXY: return TStringBuf("Spider proxy no proxy alive in region"); - case HTTP_PROXY_ERROR: + case HTTP_PROXY_ERROR: return TStringBuf("Spider proxy returned custom error"); - case HTTP_SSL_ERROR: + case HTTP_SSL_ERROR: return TStringBuf("Ssl library returned error"); - case HTTP_CACHED_COPY_NOT_FOUND: + case HTTP_CACHED_COPY_NOT_FOUND: return TStringBuf("Cached copy for the url is not available"); - case HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING: + case HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING: return TStringBuf("Timed out while bytes receiving"); - // TODO: messages for >2000 codes + // TODO: messages for >2000 codes - default: + default: return TStringBuf("Unknown HTTP code"); } } diff --git a/library/cpp/http/fetch/exthttpcodes.h b/library/cpp/http/fetch/exthttpcodes.h index 537e4ac6df..6b525052cd 100644 --- a/library/cpp/http/fetch/exthttpcodes.h +++ b/library/cpp/http/fetch/exthttpcodes.h @@ -5,110 +5,110 @@ enum ExtHttpCodes { // Custom - HTTP_EXTENDED = 1000, - HTTP_BAD_RESPONSE_HEADER = 1000, - HTTP_CONNECTION_LOST = 1001, - HTTP_BODY_TOO_LARGE = 1002, - HTTP_ROBOTS_TXT_DISALLOW = 1003, - HTTP_BAD_URL = 1004, - HTTP_BAD_MIME = 1005, - HTTP_DNS_FAILURE = 1006, - HTTP_BAD_STATUS_CODE = 1007, - HTTP_BAD_HEADER_STRING = 1008, - HTTP_BAD_CHUNK = 1009, - HTTP_CONNECT_FAILED = 1010, - HTTP_FILTER_DISALLOW = 1011, - HTTP_LOCAL_EIO = 1012, - HTTP_BAD_CONTENT_LENGTH = 1013, - HTTP_BAD_ENCODING = 1014, - HTTP_LENGTH_UNKNOWN = 1015, - HTTP_HEADER_EOF = 1016, - HTTP_MESSAGE_EOF = 1017, - HTTP_CHUNK_EOF = 1018, - HTTP_PAST_EOF = 1019, - HTTP_HEADER_TOO_LARGE = 1020, - HTTP_URL_TOO_LARGE = 1021, - HTTP_INTERRUPTED = 1022, - HTTP_CUSTOM_NOT_MODIFIED = 1023, - HTTP_BAD_CONTENT_ENCODING = 1024, - HTTP_NO_RESOURCES = 1025, - HTTP_FETCHER_SHUTDOWN = 1026, - HTTP_CHUNK_TOO_LARGE = 1027, - HTTP_SERVER_BUSY = 1028, - HTTP_SERVICE_UNKNOWN = 1029, - HTTP_PROXY_UNKNOWN = 1030, - HTTP_PROXY_REQUEST_TIME_OUT = 1031, - HTTP_PROXY_INTERNAL_ERROR = 1032, - HTTP_PROXY_CONNECT_FAILED = 1033, - HTTP_PROXY_CONNECTION_LOST = 1034, - HTTP_PROXY_NO_PROXY = 1035, - HTTP_PROXY_ERROR = 1036, - HTTP_SSL_ERROR = 1037, - HTTP_CACHED_COPY_NOT_FOUND = 1038, + HTTP_EXTENDED = 1000, + HTTP_BAD_RESPONSE_HEADER = 1000, + HTTP_CONNECTION_LOST = 1001, + HTTP_BODY_TOO_LARGE = 1002, + HTTP_ROBOTS_TXT_DISALLOW = 1003, + HTTP_BAD_URL = 1004, + HTTP_BAD_MIME = 1005, + HTTP_DNS_FAILURE = 1006, + HTTP_BAD_STATUS_CODE = 1007, + HTTP_BAD_HEADER_STRING = 1008, + HTTP_BAD_CHUNK = 1009, + HTTP_CONNECT_FAILED = 1010, + HTTP_FILTER_DISALLOW = 1011, + HTTP_LOCAL_EIO = 1012, + HTTP_BAD_CONTENT_LENGTH = 1013, + HTTP_BAD_ENCODING = 1014, + HTTP_LENGTH_UNKNOWN = 1015, + HTTP_HEADER_EOF = 1016, + HTTP_MESSAGE_EOF = 1017, + HTTP_CHUNK_EOF = 1018, + HTTP_PAST_EOF = 1019, + HTTP_HEADER_TOO_LARGE = 1020, + HTTP_URL_TOO_LARGE = 1021, + HTTP_INTERRUPTED = 1022, + HTTP_CUSTOM_NOT_MODIFIED = 1023, + HTTP_BAD_CONTENT_ENCODING = 1024, + HTTP_NO_RESOURCES = 1025, + HTTP_FETCHER_SHUTDOWN = 1026, + HTTP_CHUNK_TOO_LARGE = 1027, + HTTP_SERVER_BUSY = 1028, + HTTP_SERVICE_UNKNOWN = 1029, + HTTP_PROXY_UNKNOWN = 1030, + HTTP_PROXY_REQUEST_TIME_OUT = 1031, + HTTP_PROXY_INTERNAL_ERROR = 1032, + HTTP_PROXY_CONNECT_FAILED = 1033, + HTTP_PROXY_CONNECTION_LOST = 1034, + HTTP_PROXY_NO_PROXY = 1035, + HTTP_PROXY_ERROR = 1036, + HTTP_SSL_ERROR = 1037, + HTTP_CACHED_COPY_NOT_FOUND = 1038, HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING = 1039, - HTTP_FETCHER_BAD_RESPONSE = 1040, - HTTP_FETCHER_MB_ERROR = 1041, - HTTP_SSL_CERT_ERROR = 1042, - HTTP_PROXY_REQUEST_CANCELED = 1051, + HTTP_FETCHER_BAD_RESPONSE = 1040, + HTTP_FETCHER_MB_ERROR = 1041, + HTTP_SSL_CERT_ERROR = 1042, + HTTP_PROXY_REQUEST_CANCELED = 1051, // Custom (replace HTTP 200/304) - EXT_HTTP_EXT_SUCCESS_BEGIN = 2000, // to check if code variable is in success interval - EXT_HTTP_MIRRMOVE = 2000, - EXT_HTTP_MANUAL_DELETE = 2001, - EXT_HTTP_NOTUSED2 = 2002, - EXT_HTTP_NOTUSED3 = 2003, - EXT_HTTP_REFRESH = 2004, - EXT_HTTP_NOINDEX = 2005, - EXT_HTTP_BADCODES = 2006, - EXT_HTTP_SITESTAT = 2007, - EXT_HTTP_IOERROR = 2008, - EXT_HTTP_BASEERROR = 2009, - EXT_HTTP_PARSERROR = 2010, - EXT_HTTP_BAD_CHARSET = 2011, - EXT_HTTP_BAD_LANGUAGE = 2012, - EXT_HTTP_NUMERERROR = 2013, - EXT_HTTP_EMPTYDOC = 2014, - EXT_HTTP_HUGEDOC = 2015, - EXT_HTTP_LINKGARBAGE = 2016, - EXT_HTTP_EXDUPLICATE = 2017, - EXT_HTTP_FILTERED = 2018, - EXT_HTTP_PARSERFAIL = 2019, // parser crashed (in this case image spider will redownload such document) - EXT_HTTP_GZIPERROR = 2020, - EXT_HTTP_CLEANPARAM = 2021, - EXT_HTTP_MANUAL_DELETE_URL = 2022, - EXT_HTTP_CUSTOM_PARTIAL_CONTENT = 2023, - EXT_HTTP_EMPTY_RESPONSE = 2024, - EXT_HTTP_REL_CANONICAL = 2025, + EXT_HTTP_EXT_SUCCESS_BEGIN = 2000, // to check if code variable is in success interval + EXT_HTTP_MIRRMOVE = 2000, + EXT_HTTP_MANUAL_DELETE = 2001, + EXT_HTTP_NOTUSED2 = 2002, + EXT_HTTP_NOTUSED3 = 2003, + EXT_HTTP_REFRESH = 2004, + EXT_HTTP_NOINDEX = 2005, + EXT_HTTP_BADCODES = 2006, + EXT_HTTP_SITESTAT = 2007, + EXT_HTTP_IOERROR = 2008, + EXT_HTTP_BASEERROR = 2009, + EXT_HTTP_PARSERROR = 2010, + EXT_HTTP_BAD_CHARSET = 2011, + EXT_HTTP_BAD_LANGUAGE = 2012, + EXT_HTTP_NUMERERROR = 2013, + EXT_HTTP_EMPTYDOC = 2014, + EXT_HTTP_HUGEDOC = 2015, + EXT_HTTP_LINKGARBAGE = 2016, + EXT_HTTP_EXDUPLICATE = 2017, + EXT_HTTP_FILTERED = 2018, + EXT_HTTP_PARSERFAIL = 2019, // parser crashed (in this case image spider will redownload such document) + EXT_HTTP_GZIPERROR = 2020, + EXT_HTTP_CLEANPARAM = 2021, + EXT_HTTP_MANUAL_DELETE_URL = 2022, + EXT_HTTP_CUSTOM_PARTIAL_CONTENT = 2023, + EXT_HTTP_EMPTY_RESPONSE = 2024, + EXT_HTTP_REL_CANONICAL = 2025, - EXT_HTTP_EXT_SUCCESS_END = 3000, // to check if code variable is in success interval - EXT_HTTP_HOSTFILTER = 3001, - EXT_HTTP_URLFILTER = 3002, - EXT_HTTP_SUFFIXFILTER = 3003, - EXT_HTTP_DOMAINFILTER = 3004, - EXT_HTTP_EXTDOMAINFILTER = 3005, - EXT_HTTP_PORTFILTER = 3006, - EXT_HTTP_MIRROR = 3007, - EXT_HTTP_DEEPDIR = 3008, - EXT_HTTP_DUPDIRS = 3009, - EXT_HTTP_REGEXP = 3010, - EXT_HTTP_OLDDELETED = 3012, - EXT_HTTP_PENALTY = 3013, - EXT_HTTP_POLICY = 3015, - EXT_HTTP_TOOOLD = 3016, - EXT_HTTP_GARBAGE = 3017, - EXT_HTTP_FOREIGN = 3018, - EXT_HTTP_EXT_REGEXP = 3019, - EXT_HTTP_HOPS = 3020, - EXT_HTTP_SELRANK = 3021, - EXT_HTTP_NOLINKS = 3022, - EXT_HTTP_WRONGMULTILANG = 3023, - EXT_HTTP_SOFTMIRRORS = 3024, - EXT_HTTP_BIGLEVEL = 3025, + EXT_HTTP_EXT_SUCCESS_END = 3000, // to check if code variable is in success interval + EXT_HTTP_HOSTFILTER = 3001, + EXT_HTTP_URLFILTER = 3002, + EXT_HTTP_SUFFIXFILTER = 3003, + EXT_HTTP_DOMAINFILTER = 3004, + EXT_HTTP_EXTDOMAINFILTER = 3005, + EXT_HTTP_PORTFILTER = 3006, + EXT_HTTP_MIRROR = 3007, + EXT_HTTP_DEEPDIR = 3008, + EXT_HTTP_DUPDIRS = 3009, + EXT_HTTP_REGEXP = 3010, + EXT_HTTP_OLDDELETED = 3012, + EXT_HTTP_PENALTY = 3013, + EXT_HTTP_POLICY = 3015, + EXT_HTTP_TOOOLD = 3016, + EXT_HTTP_GARBAGE = 3017, + EXT_HTTP_FOREIGN = 3018, + EXT_HTTP_EXT_REGEXP = 3019, + EXT_HTTP_HOPS = 3020, + EXT_HTTP_SELRANK = 3021, + EXT_HTTP_NOLINKS = 3022, + EXT_HTTP_WRONGMULTILANG = 3023, + EXT_HTTP_SOFTMIRRORS = 3024, + EXT_HTTP_BIGLEVEL = 3025, // fast robot codes - EXT_HTTP_FASTHOPS = 4000, - EXT_HTTP_NODOC = 4001, + EXT_HTTP_FASTHOPS = 4000, + EXT_HTTP_NODOC = 4001, EXT_HTTP_MAX }; @@ -116,26 +116,26 @@ enum ExtHttpCodes { enum HttpFlags { // connection ShouldDisconnect = 1, - ShouldRetry = 2, + ShouldRetry = 2, // UNUSED 4 // indexer - ShouldReindex = 8, - ShouldDelete = 16, - CheckLocation = 32, - CheckLinks = 64, - MarkSuspect = 128, + ShouldReindex = 8, + ShouldDelete = 16, + CheckLocation = 32, + CheckLinks = 64, + MarkSuspect = 128, // UNUSED 256 // UNUSED 512 - MoveRedir = 1024, - CanBeFake = 2048, + MoveRedir = 1024, + CanBeFake = 2048, }; const size_t EXT_HTTP_CODE_MAX = 1 << 12; static inline int Http2Status(int code) { - extern ui16* http2status; - return http2status[code & (EXT_HTTP_CODE_MAX - 1)]; + extern ui16* http2status; + return http2status[code & (EXT_HTTP_CODE_MAX - 1)]; } TStringBuf ExtHttpCodeStr(int code) noexcept; diff --git a/library/cpp/http/fetch/http_digest.cpp b/library/cpp/http/fetch/http_digest.cpp index 79c5a25319..1eaa02b7f2 100644 --- a/library/cpp/http/fetch/http_digest.cpp +++ b/library/cpp/http/fetch/http_digest.cpp @@ -1,5 +1,5 @@ -#include "http_digest.h" - +#include "http_digest.h" + #include <library/cpp/digest/md5/md5.h> #include <util/stream/output.h> #include <util/stream/str.h> @@ -9,76 +9,76 @@ static const char* WWW_PREFIX = "Authorization: Digest "; /************************************************************/ -httpDigestHandler::httpDigestHandler() - : User_(nullptr) - , Password_(nullptr) - , Nonce_(nullptr) - , NonceCount_(0) - , HeaderInstruction_(nullptr) +httpDigestHandler::httpDigestHandler() + : User_(nullptr) + , Password_(nullptr) + , Nonce_(nullptr) + , NonceCount_(0) + , HeaderInstruction_(nullptr) { } /************************************************************/ -httpDigestHandler::~httpDigestHandler() { +httpDigestHandler::~httpDigestHandler() { clear(); } /************************************************************/ -void httpDigestHandler::clear() { - free(Nonce_); - free(HeaderInstruction_); +void httpDigestHandler::clear() { + free(Nonce_); + free(HeaderInstruction_); User_ = Password_ = nullptr; Nonce_ = HeaderInstruction_ = nullptr; - NonceCount_ = 0; + NonceCount_ = 0; } /************************************************************/ -void httpDigestHandler::setAuthorization(const char* user, const char* password) { +void httpDigestHandler::setAuthorization(const char* user, const char* password) { clear(); - if (user && password) { - User_ = user; - Password_ = password; + if (user && password) { + User_ = user; + Password_ = password; } } /************************************************************/ -const char* httpDigestHandler::getHeaderInstruction() const { - return HeaderInstruction_; +const char* httpDigestHandler::getHeaderInstruction() const { + return HeaderInstruction_; } /************************************************************/ -void httpDigestHandler::generateCNonce(char* outCNonce) { +void httpDigestHandler::generateCNonce(char* outCNonce) { if (!*outCNonce) sprintf(outCNonce, "%ld", (long)time(nullptr)); } /************************************************************/ -inline void addMD5(MD5& ctx, const char* value) { +inline void addMD5(MD5& ctx, const char* value) { ctx.Update((const unsigned char*)(value), strlen(value)); } -inline void addMD5(MD5& ctx, const char* value, int len) { +inline void addMD5(MD5& ctx, const char* value, int len) { ctx.Update((const unsigned char*)(value), len); } -inline void addMD5Sep(MD5& ctx) { +inline void addMD5Sep(MD5& ctx) { addMD5(ctx, ":", 1); } /************************************************************/ /* calculate H(A1) as per spec */ -void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd, - char* outSessionKey, - char* outCNonce) { +void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd, + char* outSessionKey, + char* outCNonce) { MD5 ctx; ctx.Init(); - addMD5(ctx, User_); - addMD5Sep(ctx); - addMD5(ctx, hd.realm); - addMD5Sep(ctx); - addMD5(ctx, Password_); + addMD5(ctx, User_); + addMD5Sep(ctx); + addMD5(ctx, hd.realm); + addMD5Sep(ctx); + addMD5(ctx, Password_); - if (hd.algorithm == 1) { //MD5-sess + if (hd.algorithm == 1) { //MD5-sess unsigned char digest[16]; ctx.Final(digest); @@ -86,91 +86,91 @@ void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd, ctx.Init(); ctx.Update(digest, 16); - addMD5Sep(ctx); - addMD5(ctx, hd.nonce); - addMD5Sep(ctx); - addMD5(ctx, outCNonce); + addMD5Sep(ctx); + addMD5(ctx, hd.nonce); + addMD5Sep(ctx); + addMD5(ctx, outCNonce); ctx.End(outSessionKey); } - ctx.End(outSessionKey); + ctx.End(outSessionKey); }; /************************************************************/ /* calculate request-digest/response-digest as per HTTP Digest spec */ -void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd, - const char* path, - const char* method, - const char* nonceCount, - char* outResponse, - char* outCNonce) { +void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd, + const char* path, + const char* method, + const char* nonceCount, + char* outResponse, + char* outCNonce) { char HA1[33]; digestCalcHA1(hd, HA1, outCNonce); char HA2[33]; MD5 ctx; ctx.Init(); - addMD5(ctx, method); - addMD5Sep(ctx); - addMD5(ctx, path); + addMD5(ctx, method); + addMD5Sep(ctx); + addMD5(ctx, path); //ignore auth-int ctx.End(HA2); ctx.Init(); - addMD5(ctx, HA1, 32); - addMD5Sep(ctx); - addMD5(ctx, Nonce_); - addMD5Sep(ctx); + addMD5(ctx, HA1, 32); + addMD5Sep(ctx); + addMD5(ctx, Nonce_); + addMD5Sep(ctx); - if (hd.qop_auth) { + if (hd.qop_auth) { if (!*outCNonce) generateCNonce(outCNonce); - addMD5(ctx, nonceCount, 8); - addMD5Sep(ctx); - addMD5(ctx, outCNonce); - addMD5Sep(ctx); - addMD5(ctx, "auth", 4); - addMD5Sep(ctx); + addMD5(ctx, nonceCount, 8); + addMD5Sep(ctx); + addMD5(ctx, outCNonce); + addMD5Sep(ctx); + addMD5(ctx, "auth", 4); + addMD5Sep(ctx); } - addMD5(ctx, HA2, 32); + addMD5(ctx, HA2, 32); ctx.End(outResponse); } /************************************************************/ -bool httpDigestHandler::processHeader(const THttpAuthHeader* header, - const char* path, - const char* method, - const char* cnonce) { - if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce) +bool httpDigestHandler::processHeader(const THttpAuthHeader* header, + const char* path, + const char* method, + const char* cnonce) { + if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce) return false; - if (Nonce_) { - if (strcmp(Nonce_, header->nonce)) { - free(Nonce_); + if (Nonce_) { + if (strcmp(Nonce_, header->nonce)) { + free(Nonce_); Nonce_ = nullptr; - NonceCount_ = 0; + NonceCount_ = 0; } } - if (!Nonce_) { - Nonce_ = strdup(header->nonce); - NonceCount_ = 0; + if (!Nonce_) { + Nonce_ = strdup(header->nonce); + NonceCount_ = 0; } - free(HeaderInstruction_); + free(HeaderInstruction_); HeaderInstruction_ = nullptr; - NonceCount_++; + NonceCount_++; char nonceCount[20]; - sprintf(nonceCount, "%08d", NonceCount_); + sprintf(nonceCount, "%08d", NonceCount_); char CNonce[50]; if (cnonce) strcpy(CNonce, cnonce); else - CNonce[0] = 0; + CNonce[0] = 0; char response[33]; - digestCalcResponse(*header, path, method, nonceCount, response, CNonce); + digestCalcResponse(*header, path, method, nonceCount, response, CNonce); //digest-response = 1#( username | realm | nonce | digest-uri // | response | [ algorithm ] | [cnonce] | @@ -178,11 +178,11 @@ bool httpDigestHandler::processHeader(const THttpAuthHeader* header, // [nonce-count] | [auth-param] ) TStringStream out; - out << WWW_PREFIX << "username=\"" << User_ << "\""; + out << WWW_PREFIX << "username=\"" << User_ << "\""; out << ", realm=\"" << header->realm << "\""; out << ", nonce=\"" << header->nonce << "\""; out << ", uri=\"" << path << "\""; - if (header->algorithm == 1) + if (header->algorithm == 1) out << ", algorithm=MD5-sess"; else out << ", algorithm=MD5"; @@ -197,7 +197,7 @@ bool httpDigestHandler::processHeader(const THttpAuthHeader* header, out << "\r\n"; TString s_out = out.Str(); - HeaderInstruction_ = strdup(s_out.c_str()); + HeaderInstruction_ = strdup(s_out.c_str()); return true; } diff --git a/library/cpp/http/fetch/http_digest.h b/library/cpp/http/fetch/http_digest.h index 958737a6ac..3b1872d70b 100644 --- a/library/cpp/http/fetch/http_digest.h +++ b/library/cpp/http/fetch/http_digest.h @@ -1,46 +1,46 @@ #pragma once -#include "httpheader.h" - +#include "httpheader.h" + #include <util/system/compat.h> #include <library/cpp/http/misc/httpcodes.h> -class httpDigestHandler { -protected: - const char* User_; - const char* Password_; - char* Nonce_; - int NonceCount_; - char* HeaderInstruction_; +class httpDigestHandler { +protected: + const char* User_; + const char* Password_; + char* Nonce_; + int NonceCount_; + char* HeaderInstruction_; void clear(); - void generateCNonce(char* outCNonce); + void generateCNonce(char* outCNonce); - void digestCalcHA1(const THttpAuthHeader& hd, - char* outSessionKey, - char* outCNonce); + void digestCalcHA1(const THttpAuthHeader& hd, + char* outSessionKey, + char* outCNonce); - void digestCalcResponse(const THttpAuthHeader& hd, - const char* method, - const char* path, - const char* nonceCount, - char* outResponse, - char* outCNonce); + void digestCalcResponse(const THttpAuthHeader& hd, + const char* method, + const char* path, + const char* nonceCount, + char* outResponse, + char* outCNonce); -public: +public: httpDigestHandler(); ~httpDigestHandler(); - void setAuthorization(const char* user, - const char* password); - bool processHeader(const THttpAuthHeader* header, - const char* path, - const char* method, - const char* cnonce = nullptr); + void setAuthorization(const char* user, + const char* password); + bool processHeader(const THttpAuthHeader* header, + const char* path, + const char* method, + const char* cnonce = nullptr); - bool empty() const { - return (!User_); + bool empty() const { + return (!User_); } const char* getHeaderInstruction() const; diff --git a/library/cpp/http/fetch/http_socket.cpp b/library/cpp/http/fetch/http_socket.cpp index 7a5b29668c..1524ef04a8 100644 --- a/library/cpp/http/fetch/http_socket.cpp +++ b/library/cpp/http/fetch/http_socket.cpp @@ -7,7 +7,7 @@ #include <gcrypt.h> #include <gnutls/gnutls.h> -#include <util/network/init.h> +#include <util/network/init.h> #include <util/network/socket.h> #include <util/system/mutex.h> @@ -15,75 +15,75 @@ // HTTPS handler is used as implementation of // socketAbstractHandler for work through HTTPS protocol -class socketSecureHandler: public socketRegularHandler { -protected: - bool IsValid_; - gnutls_session Session_; - gnutls_certificate_credentials Credits_; - -public: - socketSecureHandler(); - virtual ~socketSecureHandler(); - - virtual bool Good(); - virtual int Connect(const TAddrList& addrs, TDuration Timeout); - virtual void Disconnect(); - virtual void shutdown(); - virtual bool send(const char* message, ssize_t messlen); - virtual bool peek(); - virtual ssize_t read(void* buffer, ssize_t buflen); +class socketSecureHandler: public socketRegularHandler { +protected: + bool IsValid_; + gnutls_session Session_; + gnutls_certificate_credentials Credits_; + +public: + socketSecureHandler(); + virtual ~socketSecureHandler(); + + virtual bool Good(); + virtual int Connect(const TAddrList& addrs, TDuration Timeout); + virtual void Disconnect(); + virtual void shutdown(); + virtual bool send(const char* message, ssize_t messlen); + virtual bool peek(); + virtual ssize_t read(void* buffer, ssize_t buflen); }; /********************************************************/ /********************************************************/ -static int gcry_pthread_mutex_init(void** priv) { +static int gcry_pthread_mutex_init(void** priv) { int err = 0; try { TMutex* lock = new TMutex; *priv = lock; - } catch (...) { + } catch (...) { err = -1; } return err; } -static int gcry_pthread_mutex_destroy(void** lock) { +static int gcry_pthread_mutex_destroy(void** lock) { delete static_cast<TMutex*>(*lock); - + return 0; } -static int gcry_pthread_mutex_lock(void** lock) { +static int gcry_pthread_mutex_lock(void** lock) { static_cast<TMutex*>(*lock)->Acquire(); return 0; } -static int gcry_pthread_mutex_unlock(void** lock) { +static int gcry_pthread_mutex_unlock(void** lock) { static_cast<TMutex*>(*lock)->Release(); return 0; } static struct gcry_thread_cbs gcry_threads_pthread = - { - GCRY_THREAD_OPTION_PTHREAD, NULL, - gcry_pthread_mutex_init, gcry_pthread_mutex_destroy, - gcry_pthread_mutex_lock, gcry_pthread_mutex_unlock, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL}; + { + GCRY_THREAD_OPTION_PTHREAD, NULL, + gcry_pthread_mutex_init, gcry_pthread_mutex_destroy, + gcry_pthread_mutex_lock, gcry_pthread_mutex_unlock, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL}; /********************************************************/ -struct https_initor { - https_initor() { - gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); +struct https_initor { + https_initor() { + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); gnutls_global_init(); - InitNetworkSubSystem(); + InitNetworkSubSystem(); } - ~https_initor() { + ~https_initor() { gnutls_global_deinit(); } }; @@ -91,112 +91,112 @@ struct https_initor { static https_initor _initor; /********************************************************/ -socketSecureHandler::socketSecureHandler() - : socketRegularHandler() - , IsValid_(false) - , Session_() - , Credits_() +socketSecureHandler::socketSecureHandler() + : socketRegularHandler() + , IsValid_(false) + , Session_() + , Credits_() { } /********************************************************/ -socketSecureHandler::~socketSecureHandler() { - if (IsValid_) +socketSecureHandler::~socketSecureHandler() { + if (IsValid_) Disconnect(); } /********************************************************/ -bool socketSecureHandler::Good() { - return Socket_.Good() && IsValid_; +bool socketSecureHandler::Good() { + return Socket_.Good() && IsValid_; } /********************************************************/ -int socketSecureHandler::Connect(const TAddrList& addrs, TDuration Timeout) { - IsValid_ = false; +int socketSecureHandler::Connect(const TAddrList& addrs, TDuration Timeout) { + IsValid_ = false; int ret = socketRegularHandler::Connect(addrs, Timeout); if (ret) return ret; - gnutls_certificate_allocate_credentials(&Credits_); - gnutls_init(&Session_, GNUTLS_CLIENT); - gnutls_set_default_priority(Session_); - gnutls_credentials_set(Session_, GNUTLS_CRD_CERTIFICATE, Credits_); + gnutls_certificate_allocate_credentials(&Credits_); + gnutls_init(&Session_, GNUTLS_CLIENT); + gnutls_set_default_priority(Session_); + gnutls_credentials_set(Session_, GNUTLS_CRD_CERTIFICATE, Credits_); - SOCKET fd = Socket_; - gnutls_transport_set_ptr(Session_, (gnutls_transport_ptr)fd); + SOCKET fd = Socket_; + gnutls_transport_set_ptr(Session_, (gnutls_transport_ptr)fd); - ret = gnutls_handshake(Session_); + ret = gnutls_handshake(Session_); - if (ret < 0) { + if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); - gnutls_deinit(Session_); - if (Credits_) { - gnutls_certificate_free_credentials(Credits_); - Credits_ = 0; + gnutls_deinit(Session_); + if (Credits_) { + gnutls_certificate_free_credentials(Credits_); + Credits_ = 0; } return 1; } - IsValid_ = true; - return !IsValid_; + IsValid_ = true; + return !IsValid_; } /********************************************************/ -void socketSecureHandler::Disconnect() { - if (IsValid_) { - gnutls_bye(Session_, GNUTLS_SHUT_RDWR); - IsValid_ = false; - gnutls_deinit(Session_); +void socketSecureHandler::Disconnect() { + if (IsValid_) { + gnutls_bye(Session_, GNUTLS_SHUT_RDWR); + IsValid_ = false; + gnutls_deinit(Session_); } - if (Credits_) { - gnutls_certificate_free_credentials(Credits_); - Credits_ = 0; + if (Credits_) { + gnutls_certificate_free_credentials(Credits_); + Credits_ = 0; } socketRegularHandler::Disconnect(); } /********************************************************/ -void socketSecureHandler::shutdown() { +void socketSecureHandler::shutdown() { } /********************************************************/ -bool socketSecureHandler::send(const char* message, ssize_t messlen) { - if (!IsValid_) +bool socketSecureHandler::send(const char* message, ssize_t messlen) { + if (!IsValid_) return false; - ssize_t rv = gnutls_record_send(Session_, message, messlen); + ssize_t rv = gnutls_record_send(Session_, message, messlen); return rv >= 0; } /********************************************************/ -bool socketSecureHandler::peek() { +bool socketSecureHandler::peek() { //ssize_t rv = gnutls_record_check_pending(mSession); //return rv>0; return true; } /********************************************************/ -ssize_t socketSecureHandler::read(void* buffer, ssize_t buflen) { - if (!IsValid_) +ssize_t socketSecureHandler::read(void* buffer, ssize_t buflen) { + if (!IsValid_) return false; - return gnutls_record_recv(Session_, (char*)buffer, buflen); + return gnutls_record_recv(Session_, (char*)buffer, buflen); } #endif /************************************************************/ -socketAbstractHandler* socketHandlerFactory::chooseHandler(const THttpURL& url) { - if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTP) +socketAbstractHandler* socketHandlerFactory::chooseHandler(const THttpURL& url) { + if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTP) return new socketRegularHandler; -#ifdef USE_GNUTLS - if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTPS) +#ifdef USE_GNUTLS + if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTPS) return new socketSecureHandler; -#endif +#endif return nullptr; } diff --git a/library/cpp/http/fetch/httpfetcher.h b/library/cpp/http/fetch/httpfetcher.h index 4b02eef5fc..7fc251afd2 100644 --- a/library/cpp/http/fetch/httpfetcher.h +++ b/library/cpp/http/fetch/httpfetcher.h @@ -1,7 +1,7 @@ #pragma once #ifdef _MSC_VER -#include <io.h> +#include <io.h> #endif #include <library/cpp/http/misc/httpdate.h> @@ -10,27 +10,27 @@ #include "httpparser.h" struct TFakeBackup { - int Write(void* /*buf*/, size_t /*size*/) { - return 0; - } + int Write(void* /*buf*/, size_t /*size*/) { + return 0; + } }; template <size_t bufsize = 5000> struct TFakeAlloc { - void Shrink(void* /*buf*/, size_t /*size*/) { - } - void* Grab(size_t /*min*/, size_t* real) { - *real = bufsize; - return buf; - } - char buf[bufsize]; + void Shrink(void* /*buf*/, size_t /*size*/) { + } + void* Grab(size_t /*min*/, size_t* real) { + *real = bufsize; + return buf; + } + char buf[bufsize]; }; -template <typename TAlloc = TFakeAlloc<>, - typename TCheck = TFakeCheck<>, +template <typename TAlloc = TFakeAlloc<>, + typename TCheck = TFakeCheck<>, typename TWriter = TFakeBackup, - typename TAgent = THttpAgent<>> -class THttpFetcher: public THttpParser<TCheck>, public TAlloc, public TWriter, public TAgent { + typename TAgent = THttpAgent<>> +class THttpFetcher: public THttpParser<TCheck>, public TAlloc, public TWriter, public TAgent { public: static const size_t TCP_MIN = 1500; static int TerminateNow; @@ -40,21 +40,21 @@ public: , TAlloc() , TWriter() , TAgent() - { - } + { + } - virtual ~THttpFetcher() { - } + virtual ~THttpFetcher() { + } - int Fetch(THttpHeader* header, const char* path, const char* const* headers, int persistent, bool head_request = false) { + int Fetch(THttpHeader* header, const char* path, const char* const* headers, int persistent, bool head_request = false) { int ret = 0; int fetcherr = 0; THttpParser<TCheck>::Init(header, head_request); - const char* scheme = HttpUrlSchemeKindToString((THttpURL::TSchemeKind)TAgent::GetScheme()); + const char* scheme = HttpUrlSchemeKindToString((THttpURL::TSchemeKind)TAgent::GetScheme()); size_t schemelen = strlen(scheme); if (*path == '/') { - header->base = TStringBuf(scheme, schemelen); + header->base = TStringBuf(scheme, schemelen); header->base += TStringBuf("://", 3); header->base += TStringBuf(TAgent::pHostBeg, TAgent::pHostEnd - TAgent::pHostBeg); header->base += path; @@ -95,9 +95,9 @@ public: } if ((got = TAgent::read(bufptr, buffree)) < 0) { fetcherr = errno; - if (errno == EINTR) + if (errno == EINTR) header->error = HTTP_INTERRUPTED; - else if (errno == ETIMEDOUT) + else if (errno == ETIMEDOUT) header->error = HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING; else header->error = HTTP_CONNECTION_LOST; @@ -113,7 +113,7 @@ public: THttpParser<TCheck>::Parse(parsebuf, got); if (header->error) - break; //if ANY error ocurred we will stop download that file or will have unprognosed stream position until MAX size reached + break; //if ANY error ocurred we will stop download that file or will have unprognosed stream position until MAX size reached if (inheader && THttpParser<TCheck>::GetState() != THttpParser<TCheck>::hp_in_header) { inheader = 0; @@ -141,12 +141,12 @@ public: i64 Adjustment = 0; if (!header->error) { - if (header->transfer_chunked) { + if (header->transfer_chunked) { Adjustment = header->header_size + header->entity_size - bufsize - 1; - } else if (header->content_length >= 0) { + } else if (header->content_length >= 0) { Adjustment = header->header_size + header->content_length - bufsize; } - if (Adjustment > 0) + if (Adjustment > 0) Adjustment = 0; } diff --git a/library/cpp/http/fetch/httpfsm.h b/library/cpp/http/fetch/httpfsm.h index af490adc5a..c4abdcd0d2 100644 --- a/library/cpp/http/fetch/httpfsm.h +++ b/library/cpp/http/fetch/httpfsm.h @@ -1,7 +1,7 @@ #pragma once -#include "httpheader.h" - +#include "httpheader.h" + #include <util/system/maxlen.h> #include <util/datetime/parser.h> @@ -15,7 +15,7 @@ struct THttpHeaderParser { static constexpr int NeedMore = 1; static constexpr int Accepted = 2; - int Execute(const void* inBuf, size_t len) { + int Execute(const void* inBuf, size_t len) { return execute((unsigned char*)inBuf, (int)len); } @@ -23,7 +23,7 @@ struct THttpHeaderParser { return Execute(str.data(), str.size()); } - int Init(THttpHeader* h) { + int Init(THttpHeader* h) { int ret = Init((THttpBaseHeader*)(h)); hd = h; hd->Init(); @@ -32,43 +32,43 @@ struct THttpHeaderParser { return ret; } - int Init(THttpAuthHeader* h) { + int Init(THttpAuthHeader* h) { int ret = Init((THttpHeader*)(h)); auth_hd = h; return ret; } - int Init(THttpRequestHeader* h) { + int Init(THttpRequestHeader* h) { int ret = Init((THttpBaseHeader*)(h)); request_hd = h; request_hd->Init(); return ret; } - THttpHeader* hd; - long I; - int Dc; + THttpHeader* hd; + long I; + int Dc; TDateTimeFieldsDeprecated DateTimeFields; - char buf[FETCHER_URL_MAX]; - size_t buflen; - char* lastchar; + char buf[FETCHER_URL_MAX]; + size_t buflen; + char* lastchar; - const unsigned char* langstart; - size_t langlen; + const unsigned char* langstart; + size_t langlen; - char* hreflangpos; - size_t hreflangspace; + char* hreflangpos; + size_t hreflangspace; bool AcceptingXRobots; - THttpAuthHeader* auth_hd; - THttpRequestHeader* request_hd; + THttpAuthHeader* auth_hd; + THttpRequestHeader* request_hd; private: - THttpBaseHeader* base_hd; + THttpBaseHeader* base_hd; int cs; - + private: - int Init(THttpBaseHeader* header) { + int Init(THttpBaseHeader* header) { base_hd = header; auth_hd = nullptr; request_hd = nullptr; @@ -77,12 +77,12 @@ private: return 0; } - int execute(unsigned char* inBuf, int len); + int execute(unsigned char* inBuf, int len); void init(); }; struct THttpChunkParser { - int Execute(const void* inBuf, int len) { + int Execute(const void* inBuf, int len) { return execute((unsigned char*)inBuf, len); } @@ -91,14 +91,14 @@ struct THttpChunkParser { return 0; } - int chunk_length; - char* lastchar; - long I; - int Dc; - i64 cnt64; + int chunk_length; + char* lastchar; + long I; + int Dc; + i64 cnt64; private: int cs; - int execute(unsigned char* inBuf, int len); + int execute(unsigned char* inBuf, int len); void init(); }; diff --git a/library/cpp/http/fetch/httpfsm_ut.cpp b/library/cpp/http/fetch/httpfsm_ut.cpp index d6393abd48..b018e80101 100644 --- a/library/cpp/http/fetch/httpfsm_ut.cpp +++ b/library/cpp/http/fetch/httpfsm_ut.cpp @@ -1,22 +1,22 @@ -#include "httpfsm.h" +#include "httpfsm.h" #include "library-htfetch_ut_hreflang_in.h" #include "library-htfetch_ut_hreflang_out.h" - + #include <util/generic/ptr.h> #include <library/cpp/charset/doccodes.h> #include <library/cpp/testing/unittest/registar.h> class THttpHeaderParserTestSuite: public TTestBase { UNIT_TEST_SUITE(THttpHeaderParserTestSuite); - UNIT_TEST(TestRequestHeader); - UNIT_TEST(TestSplitRequestHeader); - UNIT_TEST(TestTrailingData); - UNIT_TEST(TestProxyRequestHeader); - UNIT_TEST(TestIncorrectRequestHeader); - UNIT_TEST(TestLastModified); - UNIT_TEST(TestLastModifiedCorrupted); - UNIT_TEST(TestResponseHeaderOnRequest); - UNIT_TEST(TestRequestHeaderOnResponse); + UNIT_TEST(TestRequestHeader); + UNIT_TEST(TestSplitRequestHeader); + UNIT_TEST(TestTrailingData); + UNIT_TEST(TestProxyRequestHeader); + UNIT_TEST(TestIncorrectRequestHeader); + UNIT_TEST(TestLastModified); + UNIT_TEST(TestLastModifiedCorrupted); + UNIT_TEST(TestResponseHeaderOnRequest); + UNIT_TEST(TestRequestHeaderOnResponse); UNIT_TEST(TestXRobotsTagUnknownTags); UNIT_TEST(TestXRobotsTagMyBot); UNIT_TEST(TestXRobotsTagOtherBot); @@ -25,20 +25,20 @@ class THttpHeaderParserTestSuite: public TTestBase { UNIT_TEST(TestXRobotsTagOverridePriority); UNIT_TEST(TestXRobotsTagDoesNotBreakCharset); UNIT_TEST(TestXRobotsTagAllowsMultiline); - UNIT_TEST(TestRelCanonical); - UNIT_TEST(TestHreflang); - UNIT_TEST(TestHreflangOnLongInput); - UNIT_TEST(TestMimeType); + UNIT_TEST(TestRelCanonical); + UNIT_TEST(TestHreflang); + UNIT_TEST(TestHreflangOnLongInput); + UNIT_TEST(TestMimeType); UNIT_TEST(TestRepeatedContentEncoding); UNIT_TEST_SUITE_END(); - + private: THolder<THttpHeaderParser> httpHeaderParser; - + private: void TestStart(); void TestFinish(); - + public: void TestRequestHeader(); void TestSplitRequestHeader(); @@ -76,8 +76,8 @@ void THttpHeaderParserTestSuite::TestRequestHeader() { TestStart(); THttpRequestHeader httpRequestHeader; httpHeaderParser->Init(&httpRequestHeader); - const char* request = "GET /search?q=hi HTTP/1.1\r\n" - "Host: www.google.ru:8080\r\n\r\n"; + const char* request = "GET /search?q=hi HTTP/1.1\r\n" + "Host: www.google.ru:8080\r\n\r\n"; i32 result = httpHeaderParser->Execute(request, strlen(request)); UNIT_ASSERT_EQUAL(result, 2); UNIT_ASSERT_EQUAL(httpRequestHeader.http_method, HTTP_METHOD_GET); @@ -85,11 +85,11 @@ void THttpHeaderParserTestSuite::TestRequestHeader() { UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri, "/search?q=hi"); UNIT_ASSERT_EQUAL(httpRequestHeader.GetUrl(), "http://www.google.ru:8080/search?q=hi"); UNIT_ASSERT_EQUAL(httpHeaderParser->lastchar - request + 1, - (i32)strlen(request)); + (i32)strlen(request)); UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_response_timeout, - DEFAULT_RESPONSE_TIMEOUT); + DEFAULT_RESPONSE_TIMEOUT); UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_request_priority, - DEFAULT_REQUEST_PRIORITY); + DEFAULT_REQUEST_PRIORITY); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_sourcename, ""), 0); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_requesttype, ""), 0); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_fetchoptions, ""), 0); @@ -99,7 +99,7 @@ void THttpHeaderParserTestSuite::TestRequestHeader() { void THttpHeaderParserTestSuite::TestSplitRequestHeader() { TestStart(); - const char* request = + const char* request = "GET /search?q=hi HTTP/1.1\r\n" "Host: www.google.ru:8080 \r\n" "\r\n"; @@ -108,8 +108,8 @@ void THttpHeaderParserTestSuite::TestSplitRequestHeader() { for (size_t n1 = 0; n1 < rlen; n1++) { for (size_t n2 = n1; n2 < rlen; n2++) { TString s1{request, 0, n1}; - TString s2{request, n1, n2 - n1}; - TString s3{request, n2, rlen - n2}; + TString s2{request, n1, n2 - n1}; + TString s3{request, n2, rlen - n2}; UNIT_ASSERT_EQUAL(s1 + s2 + s3, request); THttpRequestHeader httpRequestHeader; @@ -134,7 +134,7 @@ void THttpHeaderParserTestSuite::TestTrailingData() { TestStart(); THttpRequestHeader httpRequestHeader; UNIT_ASSERT(0 == httpHeaderParser->Init(&httpRequestHeader)); - const char* request = + const char* request = "GET /search?q=hi HTTP/1.1\r\n" "Host: www.google.ru:8080\r\n" "\r\n" @@ -156,7 +156,7 @@ void THttpHeaderParserTestSuite::TestProxyRequestHeader() { TestStart(); THttpRequestHeader httpRequestHeader; httpHeaderParser->Init(&httpRequestHeader); - const char* request = + const char* request = "GET http://www.google.ru:8080/search?q=hi HTTP/1.1\r\n" "X-Yandex-Response-Timeout: 1000\r\n" "X-Yandex-Request-Priority: 2\r\n" @@ -179,16 +179,16 @@ void THttpHeaderParserTestSuite::TestProxyRequestHeader() { UNIT_ASSERT_VALUES_EQUAL(httpRequestHeader.if_modified_since, TInstant::ParseIso8601Deprecated("1994-10-29 19:43:31Z").TimeT()); UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri, - "http://www.google.ru:8080/search?q=hi"); - UNIT_ASSERT(httpRequestHeader.GetUrl() == + "http://www.google.ru:8080/search?q=hi"); + UNIT_ASSERT(httpRequestHeader.GetUrl() == "http://www.google.ru:8080/search?q=hi"); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.host, ""), 0); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.from, "webadmin@yandex.ru"), 0); UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.user_agent, - "Yandex/1.01.001 (compatible; Win16; I)"), - 0); + "Yandex/1.01.001 (compatible; Win16; I)"), + 0); UNIT_ASSERT_EQUAL(httpHeaderParser->lastchar - request + 1, - (i32)strlen(request)); + (i32)strlen(request)); TestFinish(); } @@ -196,8 +196,8 @@ void THttpHeaderParserTestSuite::TestIncorrectRequestHeader() { TestStart(); THttpRequestHeader httpRequestHeader; httpHeaderParser->Init(&httpRequestHeader); - const char* request = "GET /search?q=hi HTP/1.1\r\n" - "Host: www.google.ru:8080\r\n\r\n"; + const char* request = "GET /search?q=hi HTP/1.1\r\n" + "Host: www.google.ru:8080\r\n\r\n"; i32 result = httpHeaderParser->Execute(request, strlen(request)); UNIT_ASSERT(result != 2); TestFinish(); @@ -214,7 +214,7 @@ void THttpHeaderParserTestSuite::TestLastModified() { UNIT_ASSERT(2 == httpHeaderParser->Execute(headers, strlen(headers))); UNIT_ASSERT_VALUES_EQUAL( TInstant::ParseIso8601Deprecated("2009-08-13 14:27:08Z").TimeT(), - h.http_time); + h.http_time); TestFinish(); } @@ -235,7 +235,7 @@ void THttpHeaderParserTestSuite::TestXRobotsTagUnknownTags() { TestStart(); THttpHeader httpHeader; httpHeaderParser->Init(&httpHeader); - const char* headers = + const char* headers = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "x-robots-tag: asdfasdf asdf asdf,,, , noindex,noodpXXX , NOFOLLOW ,noodpnofollow\r\n\r\n"; @@ -384,7 +384,7 @@ void THttpHeaderParserTestSuite::TestHreflang() { TestStart(); THttpHeader httpHeader; httpHeaderParser->Init(&httpHeader); - const char* headers = + const char* headers = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "link: <http://www.high.ru/>; rel='alternate'; hreflang='x-default'\r\n" @@ -414,7 +414,7 @@ void THttpHeaderParserTestSuite::TestRelCanonical() { TestStart(); THttpHeader httpHeader; httpHeaderParser->Init(&httpHeader); - const char* headers = + const char* headers = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "Link: <http://yandex.ru>; rel = \"canonical\"\r\n\r\n"; @@ -428,8 +428,8 @@ void THttpHeaderParserTestSuite::TestResponseHeaderOnRequest() { TestStart(); THttpHeader httpHeader; httpHeaderParser->Init(&httpHeader); - const char* request = "GET /search?q=hi HTP/1.1\r\n" - "Host: www.google.ru:8080\r\n\r\n"; + const char* request = "GET /search?q=hi HTP/1.1\r\n" + "Host: www.google.ru:8080\r\n\r\n"; i32 result = httpHeaderParser->Execute(request, strlen(request)); UNIT_ASSERT_EQUAL(result, -3); TestFinish(); @@ -439,9 +439,9 @@ void THttpHeaderParserTestSuite::TestRequestHeaderOnResponse() { TestStart(); THttpRequestHeader httpRequestHeader; httpHeaderParser->Init(&httpRequestHeader); - const char* response = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Last-Modified: Thu, 13 Aug 2009 14:\r\n\r\n"; + const char* response = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Last-Modified: Thu, 13 Aug 2009 14:\r\n\r\n"; i32 result = httpHeaderParser->Execute(response, strlen(response)); UNIT_ASSERT_EQUAL(result, -3); TestFinish(); @@ -451,13 +451,13 @@ void THttpHeaderParserTestSuite::TestMimeType() { TestStart(); THttpHeader httpHeader; httpHeaderParser->Init(&httpHeader); - const char* headers = + const char* headers = "HTTP/1.1 200 OK\r\n" "Content-Type: application/json; charset=utf-8\r\n\r\n"; i32 result = httpHeaderParser->Execute(headers, strlen(headers)); UNIT_ASSERT_EQUAL(result, 2); UNIT_ASSERT_EQUAL(httpHeader.mime_type, static_cast<ui8>(MIME_JSON)); - UNIT_ASSERT_EQUAL(httpHeader.charset, static_cast<ui8>(CODES_UTF8)); + UNIT_ASSERT_EQUAL(httpHeader.charset, static_cast<ui8>(CODES_UTF8)); TestFinish(); } @@ -516,10 +516,10 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { Y_UNIT_TEST(TestWithoutEolHead) { const TStringBuf blob{ "4\r\n" - "____\r\n"}; + "____\r\n"}; TVector<int> states{ - -1, /* 1, -1, - 1, -1, 1, -1, 1, -1 */}; + -1, /* 1, -1, + 1, -1, 1, -1, 1, -1 */}; // as soon as error happens parser state should be considered // undefined, state is meaningless after the very first `-1` // moreover, testenv produces `states[1] == -1` for this input and @@ -530,7 +530,7 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { Y_UNIT_TEST(TestTrivialChunk) { const TStringBuf blob{ "\r\n" - "4\r\n"}; + "4\r\n"}; THttpChunkParser parser(parseBytesWithLastState(blob, 2)); UNIT_ASSERT_EQUAL(parser.chunk_length, 4); UNIT_ASSERT_EQUAL(parser.cnt64, 4); @@ -539,18 +539,18 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { Y_UNIT_TEST(TestNegative) { const TStringBuf blob{ "\r\n" - "-1"}; + "-1"}; TVector<int> states{ 1, 1, - -1, - /* 1 */}; + -1, + /* 1 */}; parseByteByByte(blob, states); } Y_UNIT_TEST(TestLeadingZero) { const TStringBuf blob{ "\r\n" - "042\r\n"}; + "042\r\n"}; THttpChunkParser parser(parseBytesWithLastState(blob, 2)); UNIT_ASSERT_EQUAL(parser.chunk_length, 0x42); } @@ -558,7 +558,7 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { Y_UNIT_TEST(TestIntOverflow) { const TStringBuf blob{ "\r\n" - "deadbeef"}; + "deadbeef"}; THttpChunkParser parser(parseBytesWithLastState(blob, -2)); UNIT_ASSERT_EQUAL(parser.chunk_length, 0); UNIT_ASSERT_EQUAL(parser.cnt64, 0xdeadbeef); @@ -571,9 +571,9 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { "_" // first byte of the chunk }; TVector<int> states{ - 1, 1, - 1, 1, 2, - -1}; + 1, 1, + 1, 1, 2, + -1}; parseByteByByte(blob, states); } @@ -584,7 +584,7 @@ Y_UNIT_TEST_SUITE(TestHttpChunkParser) { "\r\n" "000 ;foo = bar \r\n" "Trailer: bar\r\n" - "\r\n"}; + "\r\n"}; THttpChunkParser parser(parseBytesWithLastState(blob, 2)); UNIT_ASSERT_EQUAL(parser.chunk_length, 0); } diff --git a/library/cpp/http/fetch/httpheader.h b/library/cpp/http/fetch/httpheader.h index e779cb08ec..b2810bbd41 100644 --- a/library/cpp/http/fetch/httpheader.h +++ b/library/cpp/http/fetch/httpheader.h @@ -10,33 +10,33 @@ #include <util/generic/ylimits.h> #include <util/system/maxlen.h> -#include <ctime> +#include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> -#include <algorithm> +#include <algorithm> // 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_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 +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_UNSET = 0, + HTTP_COMPRESSION_ERROR = 1, HTTP_COMPRESSION_IDENTITY = 2, - HTTP_COMPRESSION_GZIP = 3, - HTTP_COMPRESSION_DEFLATE = 4, + HTTP_COMPRESSION_GZIP = 3, + HTTP_COMPRESSION_DEFLATE = 4, HTTP_COMPRESSION_COMPRESS = 5, - HTTP_COMPRESSION_MAX = 6 + HTTP_COMPRESSION_MAX = 6 }; enum HTTP_METHOD { @@ -61,22 +61,22 @@ enum HTTP_CONNECTION { /// 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; + 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; @@ -113,8 +113,8 @@ public: } int SetBase(const char* path, - const char* hostNamePtr = nullptr, - int hostNameLength = 0) { + const char* hostNamePtr = nullptr, + int hostNameLength = 0) { if (*path == '/') { base = "http://"; base += TStringBuf(hostNamePtr, hostNameLength); @@ -130,16 +130,16 @@ enum { HREFLANG_MAX = FETCHER_URL_MAX * 2 }; /// Class represents Http Response Header. struct THttpHeader: public THttpBaseHeader { public: - i8 accept_ranges; - i8 squid_error; + i8 accept_ranges; + i8 squid_error; i8 x_robots_tag; // deprecated, use x_robots_state instead - i16 http_status; + i16 http_status; TString location; TString rel_canonical; - char hreflangs[HREFLANG_MAX]; - i64 retry_after; + char hreflangs[HREFLANG_MAX]; + i64 retry_after; TString x_robots_state; // 'xxxxx' format, see `library/html/zoneconf/parsefunc.cpp` - + public: void Init() { THttpBaseHeader::Init(); @@ -174,12 +174,12 @@ public: 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; - + i8 http_method; + i8 x_yandex_request_priority; + i32 x_yandex_response_timeout; + i32 max_age; + i64 if_modified_since; + public: THttpRequestHeader() { Init(); @@ -229,7 +229,7 @@ public: return url; } - char* GetUrl(char* buffer, size_t size) { + char* GetUrl(char* buffer, size_t size) { if (host[0] == 0 || !strcmp(host, "")) { strlcpy(buffer, request_uri.c_str(), size); } else { @@ -244,27 +244,27 @@ public: char* realm; char* nonce; char* opaque; - bool stale; - int algorithm; - bool qop_auth; - bool use_auth; + 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) + THttpAuthHeader() + : realm(nullptr) + , nonce(nullptr) + , opaque(nullptr) + , stale(false) + , algorithm(0) + , qop_auth(false) + , use_auth(true) { THttpHeader::Init(); } - ~THttpAuthHeader() { + ~THttpAuthHeader() { free(realm); free(nonce); free(opaque); @@ -272,7 +272,7 @@ public: void Print() { THttpHeader::Print(); - if (use_auth) { + if (use_auth) { if (realm) printf("realm: \"%s\"\n", realm); if (nonce) diff --git a/library/cpp/http/fetch/httpload.cpp b/library/cpp/http/fetch/httpload.cpp index 975a8d792c..82ea8900b5 100644 --- a/library/cpp/http/fetch/httpload.cpp +++ b/library/cpp/http/fetch/httpload.cpp @@ -2,210 +2,210 @@ /************************************************************/ /************************************************************/ -httpAgentReader::httpAgentReader(httpSpecialAgent& agent, - const char* baseUrl, - bool assumeConnectionClosed, - bool use_auth, - int bufSize) - : Header_() - , Agent_(agent) - , Buffer_(new char[bufSize]) - , BufPtr_(Buffer_) - , BufSize_(bufSize) - , BufRest_(0) +httpAgentReader::httpAgentReader(httpSpecialAgent& agent, + const char* baseUrl, + bool assumeConnectionClosed, + bool use_auth, + int bufSize) + : Header_() + , Agent_(agent) + , Buffer_(new char[bufSize]) + , BufPtr_(Buffer_) + , BufSize_(bufSize) + , BufRest_(0) { HeadRequest = false; - Header = &Header_; + Header = &Header_; if (use_auth) - HeaderParser.Init(&Header_); + HeaderParser.Init(&Header_); else HeaderParser.Init(Header); - setAssumeConnectionClosed(assumeConnectionClosed ? 1 : 0); - Header_.SetBase(baseUrl); + setAssumeConnectionClosed(assumeConnectionClosed ? 1 : 0); + Header_.SetBase(baseUrl); - if (Header_.error) + if (Header_.error) State = hp_error; else State = hp_in_header; } /************************************************************/ -httpAgentReader::~httpAgentReader() { - delete[] Buffer_; +httpAgentReader::~httpAgentReader() { + delete[] Buffer_; } /************************************************************/ -void httpAgentReader::readBuf() { - assert(BufRest_ == 0); - if (!BufPtr_) { - BufRest_ = -1; +void httpAgentReader::readBuf() { + assert(BufRest_ == 0); + if (!BufPtr_) { + BufRest_ = -1; return; } - BufRest_ = Agent_.read(Buffer_, BufSize_); - if (BufRest_ <= 0) { - BufRest_ = -1; - BufPtr_ = nullptr; + BufRest_ = Agent_.read(Buffer_, BufSize_); + if (BufRest_ <= 0) { + BufRest_ = -1; + BufPtr_ = nullptr; } else { - BufPtr_ = Buffer_; - + BufPtr_ = Buffer_; + //cout << "BUF: " << mBuffer << endl << endl; } } /************************************************************/ -const THttpHeader* httpAgentReader::readHeader() { - while (State == hp_in_header) { - if (!step()) { - Header_.error = HTTP_CONNECTION_LOST; +const THttpHeader* httpAgentReader::readHeader() { + while (State == hp_in_header) { + if (!step()) { + Header_.error = HTTP_CONNECTION_LOST; return nullptr; } - ParseGeneric(BufPtr_, BufRest_); + ParseGeneric(BufPtr_, BufRest_); } - if (State == hp_eof || State == hp_error) { + if (State == hp_eof || State == hp_error) { BufPtr_ = nullptr; - BufRest_ = -1; + BufRest_ = -1; } - if (State == hp_error || Header_.error) + if (State == hp_error || Header_.error) return nullptr; - return &Header_; + return &Header_; } /************************************************************/ -long httpAgentReader::readPortion(void*& buf) { - assert(State != hp_in_header); +long httpAgentReader::readPortion(void*& buf) { + assert(State != hp_in_header); long Chunk = 0; - do { - if (BufSize_ == 0 && !BufPtr_) + do { + if (BufSize_ == 0 && !BufPtr_) return 0; if (!step()) return 0; - Chunk = ParseGeneric(BufPtr_, BufRest_); - buf = BufPtr_; + Chunk = ParseGeneric(BufPtr_, BufRest_); + buf = BufPtr_; - if (State == hp_error && Header_.entity_size > Header_.content_length) { - Chunk -= (Header_.entity_size - Header_.content_length); - BufPtr_ = (char*)BufPtr_ + Chunk; - BufRest_ = 0; - State = hp_eof; - Header_.error = 0; + if (State == hp_error && Header_.entity_size > Header_.content_length) { + Chunk -= (Header_.entity_size - Header_.content_length); + BufPtr_ = (char*)BufPtr_ + Chunk; + BufRest_ = 0; + State = hp_eof; + Header_.error = 0; break; } - BufPtr_ = (char*)BufPtr_ + Chunk; - BufRest_ -= Chunk; + BufPtr_ = (char*)BufPtr_ + Chunk; + BufRest_ -= Chunk; - if (State == hp_eof || State == hp_error) { - BufRest_ = -1; - BufPtr_ = nullptr; + if (State == hp_eof || State == hp_error) { + BufRest_ = -1; + BufPtr_ = nullptr; } } while (!Chunk); return Chunk; } /************************************************************/ -bool httpAgentReader::skipTheRest() { +bool httpAgentReader::skipTheRest() { void* b; while (!eof()) readPortion(b); - return (State == hp_eof); + return (State == hp_eof); } /************************************************************/ /************************************************************/ -httpLoadAgent::httpLoadAgent(bool handleAuthorization, - socketHandlerFactory& factory) - : Factory_(factory) - , HandleAuthorization_(handleAuthorization) - , URL_() - , PersistentConn_(false) - , Reader_(nullptr) - , Headers_() - , ErrCode_(0) - , RealHost_(nullptr) +httpLoadAgent::httpLoadAgent(bool handleAuthorization, + socketHandlerFactory& factory) + : Factory_(factory) + , HandleAuthorization_(handleAuthorization) + , URL_() + , PersistentConn_(false) + , Reader_(nullptr) + , Headers_() + , ErrCode_(0) + , RealHost_(nullptr) { } /************************************************************/ -httpLoadAgent::~httpLoadAgent() { - delete Reader_; - free(RealHost_); +httpLoadAgent::~httpLoadAgent() { + delete Reader_; + free(RealHost_); } /************************************************************/ -void httpLoadAgent::clearReader() { - if (Reader_) { +void httpLoadAgent::clearReader() { + if (Reader_) { bool opened = false; - if (PersistentConn_) { - const THttpHeader* H = Reader_->readHeader(); - if (H && !H->connection_closed) { - Reader_->skipTheRest(); + if (PersistentConn_) { + const THttpHeader* H = Reader_->readHeader(); + if (H && !H->connection_closed) { + Reader_->skipTheRest(); opened = true; } } if (!opened) Disconnect(); - delete Reader_; + delete Reader_; Reader_ = nullptr; } - ErrCode_ = 0; + ErrCode_ = 0; } /************************************************************/ -void httpLoadAgent::setRealHost(const char* hostname) { - free(RealHost_); +void httpLoadAgent::setRealHost(const char* hostname) { + free(RealHost_); if (hostname) - RealHost_ = strdup(hostname); + RealHost_ = strdup(hostname); else RealHost_ = nullptr; - ErrCode_ = 0; + ErrCode_ = 0; } /************************************************************/ -void httpLoadAgent::setIMS(const char* ifModifiedSince) { +void httpLoadAgent::setIMS(const char* ifModifiedSince) { char ims_buf[100]; snprintf(ims_buf, 100, "If-Modified-Since: %s\r\n", ifModifiedSince); - Headers_.push_back(ims_buf); + Headers_.push_back(ims_buf); } /************************************************************/ -void httpLoadAgent::addHeaderInstruction(const char* instr) { - Headers_.push_back(instr); +void httpLoadAgent::addHeaderInstruction(const char* instr) { + Headers_.push_back(instr); } /************************************************************/ -void httpLoadAgent::dropHeaderInstructions() { - Headers_.clear(); +void httpLoadAgent::dropHeaderInstructions() { + Headers_.clear(); } /************************************************************/ -bool httpLoadAgent::startRequest(const THttpURL& url, - bool persistent, - const TAddrList& addrs) +bool httpLoadAgent::startRequest(const THttpURL& url, + bool persistent, + const TAddrList& addrs) { clearReader(); - ErrCode_ = 0; + ErrCode_ = 0; - URL_.Clear(); - URL_ = url; - PersistentConn_ = persistent; - if (!URL_.IsValidAbs()) + URL_.Clear(); + URL_ = url; + PersistentConn_ = persistent; + if (!URL_.IsValidAbs()) return false; - if (!HandleAuthorization_ && !URL_.IsNull(THttpURL::FlagAuth)) + if (!HandleAuthorization_ && !URL_.IsNull(THttpURL::FlagAuth)) return false; return doSetHost(addrs) && doStartRequest(); } /************************************************************/ -bool httpLoadAgent::startRequest(const char* url, - const char* url_to_merge, - bool persistent, - const TAddrList& addrs) { +bool httpLoadAgent::startRequest(const char* url, + const char* url_to_merge, + bool persistent, + const TAddrList& addrs) { clearReader(); URL_.Clear(); @@ -222,116 +222,116 @@ bool httpLoadAgent::startRequest(const char* url, } /************************************************************/ -bool httpLoadAgent::startRequest(const char* url, - const char* url_to_merge, - bool persistent, - ui32 ip) { +bool httpLoadAgent::startRequest(const char* url, + const char* url_to_merge, + bool persistent, + ui32 ip) { clearReader(); - URL_.Clear(); - PersistentConn_ = persistent; + URL_.Clear(); + PersistentConn_ = persistent; long flags = THttpURL::FeatureSchemeKnown | THttpURL::FeaturesNormalizeSet; - if (HandleAuthorization_) + if (HandleAuthorization_) flags |= THttpURL::FeatureAuthSupported; - if (URL_.Parse(url, flags, url_to_merge) || !URL_.IsValidGlobal()) + if (URL_.Parse(url, flags, url_to_merge) || !URL_.IsValidGlobal()) return false; return doSetHost(TAddrList::MakeV4Addr(ip, URL_.GetPort())) && doStartRequest(); } /************************************************************/ -bool httpLoadAgent::doSetHost(const TAddrList& addrs) { - socketAbstractHandler* h = Factory_.chooseHandler(URL_); +bool httpLoadAgent::doSetHost(const TAddrList& addrs) { + socketAbstractHandler* h = Factory_.chooseHandler(URL_); if (!h) return false; Socket.setHandler(h); - if (addrs.size()) { - ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost), + if (addrs.size()) { + ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost), URL_.GetPort(), addrs); } else { - ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost), - URL_.GetPort()); + ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost), + URL_.GetPort()); } - if (ErrCode_) + if (ErrCode_) return false; - if (RealHost_) { + if (RealHost_) { free(Hostheader); - Hostheader = (char*)malloc(strlen(RealHost_) + 20); - sprintf(Hostheader, "Host: %s\r\n", RealHost_); + Hostheader = (char*)malloc(strlen(RealHost_) + 20); + sprintf(Hostheader, "Host: %s\r\n", RealHost_); } - if (!URL_.IsNull(THttpURL::FlagAuth)) { - if (!HandleAuthorization_) { - ErrCode_ = HTTP_UNAUTHORIZED; + if (!URL_.IsNull(THttpURL::FlagAuth)) { + if (!HandleAuthorization_) { + ErrCode_ = HTTP_UNAUTHORIZED; return false; } - Digest_.setAuthorization(URL_.Get(THttpURL::FieldUsername), - URL_.Get(THttpURL::FieldPassword)); + Digest_.setAuthorization(URL_.Get(THttpURL::FieldUsername), + URL_.Get(THttpURL::FieldPassword)); } return true; } /************************************************************/ -bool httpLoadAgent::setHost(const char* host_url, - const TAddrList& addrs) { +bool httpLoadAgent::setHost(const char* host_url, + const TAddrList& addrs) { clearReader(); - URL_.Clear(); - PersistentConn_ = true; + URL_.Clear(); + PersistentConn_ = true; long flags = THttpURL::FeatureSchemeKnown | THttpURL::FeaturesNormalizeSet; - if (HandleAuthorization_) + if (HandleAuthorization_) flags |= THttpURL::FeatureAuthSupported; - if (URL_.Parse(host_url, flags) || !URL_.IsValidGlobal()) + if (URL_.Parse(host_url, flags) || !URL_.IsValidGlobal()) return false; return doSetHost(addrs); } /************************************************************/ -bool httpLoadAgent::startOneRequest(const char* local_url) { +bool httpLoadAgent::startOneRequest(const char* local_url) { clearReader(); THttpURL lURL; - if (lURL.Parse(local_url, THttpURL::FeaturesNormalizeSet) || lURL.IsValidGlobal()) + if (lURL.Parse(local_url, THttpURL::FeaturesNormalizeSet) || lURL.IsValidGlobal()) return false; - URL_.SetInMemory(THttpURL::FieldPath, lURL.Get(THttpURL::FieldPath)); - URL_.SetInMemory(THttpURL::FieldQuery, lURL.Get(THttpURL::FieldQuery)); - URL_.Rewrite(); + URL_.SetInMemory(THttpURL::FieldPath, lURL.Get(THttpURL::FieldPath)); + URL_.SetInMemory(THttpURL::FieldQuery, lURL.Get(THttpURL::FieldQuery)); + URL_.Rewrite(); return doStartRequest(); } /************************************************************/ -bool httpLoadAgent::doStartRequest() { - TString urlStr = URL_.PrintS(THttpURL::FlagPath | THttpURL::FlagQuery); +bool httpLoadAgent::doStartRequest() { + TString urlStr = URL_.PrintS(THttpURL::FlagPath | THttpURL::FlagQuery); if (!urlStr) urlStr = "/"; - for (int step = 0; step < 10; step++) { - const char* digestHeader = Digest_.getHeaderInstruction(); + for (int step = 0; step < 10; step++) { + const char* digestHeader = Digest_.getHeaderInstruction(); - unsigned i = (digestHeader) ? 2 : 1; + unsigned i = (digestHeader) ? 2 : 1; const char** headers = - (const char**)(alloca((i + Headers_.size()) * sizeof(char*))); + (const char**)(alloca((i + Headers_.size()) * sizeof(char*))); - for (i = 0; i < Headers_.size(); i++) - headers[i] = Headers_[i].c_str(); + for (i = 0; i < Headers_.size(); i++) + headers[i] = Headers_[i].c_str(); if (digestHeader) headers[i++] = digestHeader; - headers[i] = nullptr; + headers[i] = nullptr; - ErrCode_ = RequestGet(urlStr.c_str(), headers, PersistentConn_); + ErrCode_ = RequestGet(urlStr.c_str(), headers, PersistentConn_); - if (ErrCode_) { + if (ErrCode_) { Disconnect(); return false; } @@ -339,20 +339,20 @@ bool httpLoadAgent::doStartRequest() { TString urlBaseStr = URL_.PrintS(THttpURL::FlagNoFrag); clearReader(); - Reader_ = new httpAgentReader(*this, urlBaseStr.c_str(), - !PersistentConn_, !Digest_.empty()); + Reader_ = new httpAgentReader(*this, urlBaseStr.c_str(), + !PersistentConn_, !Digest_.empty()); - if (Reader_->readHeader()) { + if (Reader_->readHeader()) { //mReader->getHeader()->Print(); - if (getHeader()->http_status == HTTP_UNAUTHORIZED && - step < 1 && - Digest_.processHeader(getAuthHeader(), - urlStr.c_str(), - "GET")) { + if (getHeader()->http_status == HTTP_UNAUTHORIZED && + step < 1 && + Digest_.processHeader(getAuthHeader(), + urlStr.c_str(), + "GET")) { //mReader->skipTheRest(); - delete Reader_; + delete Reader_; Reader_ = nullptr; - ErrCode_ = 0; + ErrCode_ = 0; Disconnect(); continue; } @@ -365,7 +365,7 @@ bool httpLoadAgent::doStartRequest() { return false; } - ErrCode_ = HTTP_UNAUTHORIZED; + ErrCode_ = HTTP_UNAUTHORIZED; return false; } diff --git a/library/cpp/http/fetch/httpload.h b/library/cpp/http/fetch/httpload.h index 5fc03d4be8..e22e4b809e 100644 --- a/library/cpp/http/fetch/httpload.h +++ b/library/cpp/http/fetch/httpload.h @@ -1,9 +1,9 @@ #pragma once -#include "httpagent.h" -#include "httpparser.h" -#include "http_digest.h" - +#include "httpagent.h" +#include "httpparser.h" +#include "http_digest.h" + #include <util/system/compat.h> #include <util/string/vector.h> #include <util/network/ip.h> @@ -20,7 +20,7 @@ /********************************************************/ // This class is used as a base one for flexible // socket handling -class socketAbstractHandler { +class socketAbstractHandler { public: virtual bool Good() = 0; @@ -36,12 +36,12 @@ public: virtual ssize_t read(void* buffer, ssize_t buflen) = 0; - virtual ~socketAbstractHandler() { - } + virtual ~socketAbstractHandler() { + } protected: - socketAbstractHandler() { - } + socketAbstractHandler() { + } }; /********************************************************/ @@ -49,54 +49,54 @@ protected: // socketAbstractHandler // (it is used by template scheme, // so it does not have virtual methods) -class TSocketHandlerPtr { +class TSocketHandlerPtr { protected: - socketAbstractHandler* Handler_; + socketAbstractHandler* Handler_; public: - TSocketHandlerPtr() - : Handler_(nullptr) - { - } + TSocketHandlerPtr() + : Handler_(nullptr) + { + } - virtual ~TSocketHandlerPtr() { - delete Handler_; - } + virtual ~TSocketHandlerPtr() { + delete Handler_; + } - int Good() { - return (Handler_ && Handler_->Good()); - } + int Good() { + return (Handler_ && Handler_->Good()); + } - int Connect(const TAddrList& addrs, TDuration Timeout) { - return (Handler_) ? Handler_->Connect(addrs, Timeout) : 1; + int Connect(const TAddrList& addrs, TDuration Timeout) { + return (Handler_) ? Handler_->Connect(addrs, Timeout) : 1; } - void Disconnect() { - if (Handler_) - Handler_->Disconnect(); + void Disconnect() { + if (Handler_) + Handler_->Disconnect(); } - void shutdown() { - if (Handler_) - Handler_->shutdown(); + void shutdown() { + if (Handler_) + Handler_->shutdown(); } - bool send(const char* message, ssize_t messlen) { - return (Handler_) ? Handler_->send(message, messlen) : false; + bool send(const char* message, ssize_t messlen) { + return (Handler_) ? Handler_->send(message, messlen) : false; } - virtual bool peek() { - return (Handler_) ? Handler_->peek() : false; + virtual bool peek() { + return (Handler_) ? Handler_->peek() : false; } - virtual ssize_t read(void* buffer, ssize_t buflen) { - return (Handler_) ? Handler_->read(buffer, buflen) : 0; + virtual ssize_t read(void* buffer, ssize_t buflen) { + return (Handler_) ? Handler_->read(buffer, buflen) : 0; } - void setHandler(socketAbstractHandler* handler) { - if (Handler_) - delete Handler_; - Handler_ = handler; + void setHandler(socketAbstractHandler* handler) { + if (Handler_) + delete Handler_; + Handler_ = handler; } }; @@ -108,58 +108,58 @@ using httpSpecialAgent = THttpAgent<TSocketHandlerPtr>; /********************************************************/ // Regular handler is used as implementation of // socketAbstractHandler for work through HTTP protocol -class socketRegularHandler: public socketAbstractHandler { -protected: - TSimpleSocketHandler Socket_; +class socketRegularHandler: public socketAbstractHandler { +protected: + TSimpleSocketHandler Socket_; -public: - socketRegularHandler() - : Socket_() - { - } +public: + socketRegularHandler() + : Socket_() + { + } - bool Good() override { - return Socket_.Good(); + bool Good() override { + return Socket_.Good(); } - int Connect(const TAddrList& addrs, TDuration Timeout) override { + int Connect(const TAddrList& addrs, TDuration Timeout) override { return Socket_.Connect(addrs, Timeout); } - void Disconnect() override { - Socket_.Disconnect(); + void Disconnect() override { + Socket_.Disconnect(); } - void shutdown() override { + void shutdown() override { //Do not block writing to socket //There are servers that works in a bad way with this //mSocket.shutdown(); } - bool send(const char* message, ssize_t messlen) override { - return Socket_.send(message, messlen); + bool send(const char* message, ssize_t messlen) override { + return Socket_.send(message, messlen); } - bool peek() override { - return Socket_.peek(); + bool peek() override { + return Socket_.peek(); } - ssize_t read(void* buffer, ssize_t buflen) override { - return Socket_.read(buffer, buflen); + ssize_t read(void* buffer, ssize_t buflen) override { + return Socket_.read(buffer, buflen); } }; /********************************************************/ // The base factory that allows to choose an appropriate // socketAbstractHandler implementation by url schema - -class socketHandlerFactory { -public: - virtual ~socketHandlerFactory() { - } + +class socketHandlerFactory { +public: + virtual ~socketHandlerFactory() { + } //returns mHandler_HTTP for correct HTTP-based url - virtual socketAbstractHandler* chooseHandler(const THttpURL& url); + virtual socketAbstractHandler* chooseHandler(const THttpURL& url); static socketHandlerFactory sInstance; }; @@ -168,138 +168,138 @@ public: // Section 2: the configurates tool to parse an HTTP-response /********************************************************/ -class httpAgentReader: public THttpParserGeneric<1> { -protected: - THttpAuthHeader Header_; - httpSpecialAgent& Agent_; +class httpAgentReader: public THttpParserGeneric<1> { +protected: + THttpAuthHeader Header_; + httpSpecialAgent& Agent_; - char* Buffer_; - void* BufPtr_; - int BufSize_; - long BufRest_; + char* Buffer_; + void* BufPtr_; + int BufSize_; + long BufRest_; void readBuf(); - bool step() { - if (BufRest_ == 0) + bool step() { + if (BufRest_ == 0) readBuf(); if (eof()) return false; return true; } -public: - httpAgentReader(httpSpecialAgent& agent, - const char* baseUrl, - bool assumeConnectionClosed, - bool use_auth = false, - int bufSize = 0x1000); +public: + httpAgentReader(httpSpecialAgent& agent, + const char* baseUrl, + bool assumeConnectionClosed, + bool use_auth = false, + int bufSize = 0x1000); ~httpAgentReader(); - bool eof() { - return BufRest_ < 0; + bool eof() { + return BufRest_ < 0; } - int error() { - return Header_.error; + int error() { + return Header_.error; } - void setError(int errCode) { - Header_.error = errCode; + void setError(int errCode) { + Header_.error = errCode; } - const THttpAuthHeader* getAuthHeader() { - return &Header_; + const THttpAuthHeader* getAuthHeader() { + return &Header_; } - const THttpHeader* readHeader(); - long readPortion(void*& buf); - bool skipTheRest(); + const THttpHeader* readHeader(); + long readPortion(void*& buf); + bool skipTheRest(); }; /********************************************************/ // Section 3: the main class /********************************************************/ -class httpLoadAgent: public httpSpecialAgent { -protected: - socketHandlerFactory& Factory_; - bool HandleAuthorization_; - THttpURL URL_; - bool PersistentConn_; - httpAgentReader* Reader_; - TVector<TString> Headers_; - int ErrCode_; - char* RealHost_; - httpDigestHandler Digest_; +class httpLoadAgent: public httpSpecialAgent { +protected: + socketHandlerFactory& Factory_; + bool HandleAuthorization_; + THttpURL URL_; + bool PersistentConn_; + httpAgentReader* Reader_; + TVector<TString> Headers_; + int ErrCode_; + char* RealHost_; + httpDigestHandler Digest_; void clearReader(); bool doSetHost(const TAddrList& addrs); bool doStartRequest(); -public: - httpLoadAgent(bool handleAuthorization = false, - socketHandlerFactory& factory = socketHandlerFactory::sInstance); +public: + httpLoadAgent(bool handleAuthorization = false, + socketHandlerFactory& factory = socketHandlerFactory::sInstance); ~httpLoadAgent(); void setRealHost(const char* host); - void setIMS(const char* ifModifiedSince); + void setIMS(const char* ifModifiedSince); void addHeaderInstruction(const char* instr); void dropHeaderInstructions(); bool startRequest(const char* url, const char* url_to_merge = nullptr, - bool persistent = false, + bool persistent = false, const TAddrList& addrs = TAddrList()); // deprecated v4-only bool startRequest(const char* url, const char* url_to_merge, - bool persistent, - ui32 ip); + bool persistent, + ui32 ip); bool startRequest(const THttpURL& url, - bool persistent = false, + bool persistent = false, const TAddrList& addrs = TAddrList()); - bool setHost(const char* host_url, - const TAddrList& addrs = TAddrList()); + bool setHost(const char* host_url, + const TAddrList& addrs = TAddrList()); bool startOneRequest(const char* local_url); - const THttpAuthHeader* getAuthHeader() { - if (Reader_ && Reader_->getAuthHeader()->use_auth) - return Reader_->getAuthHeader(); + const THttpAuthHeader* getAuthHeader() { + if (Reader_ && Reader_->getAuthHeader()->use_auth) + return Reader_->getAuthHeader(); return nullptr; } - const THttpHeader* getHeader() { - if (Reader_) - return Reader_->getAuthHeader(); + const THttpHeader* getHeader() { + if (Reader_) + return Reader_->getAuthHeader(); return nullptr; } - const THttpURL& getURL() { - return URL_; + const THttpURL& getURL() { + return URL_; } - bool eof() { - if (Reader_) - return Reader_->eof(); + bool eof() { + if (Reader_) + return Reader_->eof(); return true; } - int error() { - if (ErrCode_) - return ErrCode_; - if (Reader_) - return Reader_->error(); + int error() { + if (ErrCode_) + return ErrCode_; + if (Reader_) + return Reader_->error(); return HTTP_BAD_URL; } - long readPortion(void*& buf) { - if (Reader_) - return Reader_->readPortion(buf); + long readPortion(void*& buf) { + if (Reader_) + return Reader_->readPortion(buf); return -1; } }; diff --git a/library/cpp/http/fetch/httpparser.h b/library/cpp/http/fetch/httpparser.h index 989409bdd2..769828e4ae 100644 --- a/library/cpp/http/fetch/httpparser.h +++ b/library/cpp/http/fetch/httpparser.h @@ -6,22 +6,22 @@ #include <library/cpp/mime/types/mime.h> #include <util/system/yassert.h> #include <library/cpp/http/misc/httpcodes.h> - -template <size_t headermax = 100 << 10, size_t bodymax = 1 << 20> + +template <size_t headermax = 100 << 10, size_t bodymax = 1 << 20> struct TFakeCheck { - bool Check(THttpHeader* /*header*/) { - return false; - } - void CheckDocPart(void* /*buf*/, size_t /*len*/, THttpHeader* /*header*/) { - } //for every part of DocumentBody will be called - void CheckEndDoc(THttpHeader* /*header*/) { - } - size_t GetMaxHeaderSize() { - return headermax; - } - size_t GetMaxBodySize(THttpHeader*) { - return bodymax; - } + bool Check(THttpHeader* /*header*/) { + return false; + } + void CheckDocPart(void* /*buf*/, size_t /*len*/, THttpHeader* /*header*/) { + } //for every part of DocumentBody will be called + void CheckEndDoc(THttpHeader* /*header*/) { + } + size_t GetMaxHeaderSize() { + return headermax; + } + size_t GetMaxBodySize(THttpHeader*) { + return bodymax; + } }; class THttpParserBase { @@ -37,17 +37,17 @@ public: hp_read_chunk }; - States GetState() { - return State; - } + States GetState() { + return State; + } - void setAssumeConnectionClosed(int value) { + void setAssumeConnectionClosed(int value) { AssumeConnectionClosed = value; } - THttpHeader* GetHttpHeader() const { - return Header; - } + THttpHeader* GetHttpHeader() const { + return Header; + } protected: int CheckHeaders() { @@ -69,8 +69,8 @@ protected: if (Header->compression_method != HTTP_COMPRESSION_UNSET && Header->compression_method != HTTP_COMPRESSION_IDENTITY && Header->compression_method != HTTP_COMPRESSION_GZIP && - Header->compression_method != HTTP_COMPRESSION_DEFLATE) - { + Header->compression_method != HTTP_COMPRESSION_DEFLATE) + { Header->error = HTTP_BAD_CONTENT_ENCODING; return 1; } @@ -78,7 +78,7 @@ protected: if (Header->connection_closed == -1) Header->connection_closed = (Header->http_minor == 0 || AssumeConnectionClosed); - if (!Header->transfer_chunked && !Header->connection_closed && Header->content_length < 0 && !HeadRequest) { + if (!Header->transfer_chunked && !Header->connection_closed && Header->content_length < 0 && !HeadRequest) { Header->error = HTTP_LENGTH_UNKNOWN; return 1; } @@ -93,15 +93,15 @@ protected: THttpChunkParser ChunkParser; States State; long ChunkSize; - THttpHeader* Header; + THttpHeader* Header; int AssumeConnectionClosed; bool HeadRequest; }; -template <int isReader, typename TCheck = TFakeCheck<>> +template <int isReader, typename TCheck = TFakeCheck<>> class THttpParserGeneric: public THttpParserBase, public TCheck { protected: - long ParseGeneric(void*& buf, long& size) { + long ParseGeneric(void*& buf, long& size) { if (!size) { switch (State) { case hp_error: @@ -155,10 +155,10 @@ protected: size -= long(HeaderParser.lastchar - (char*)buf + 1); buf = HeaderParser.lastchar + 1; State = CheckHeaders() ? hp_error - : Header->transfer_chunked ? hp_begin_chunk_header - : Header->content_length == 0 ? hp_eof - : Header->content_length > 0 ? hp_read_alive - : hp_read_closed; + : Header->transfer_chunked ? hp_begin_chunk_header + : Header->content_length == 0 ? hp_eof + : Header->content_length > 0 ? hp_read_alive + : hp_read_closed; if (State == hp_begin_chunk_header) { // unget \n for chunk reader buf = (char*)buf - 1; @@ -239,11 +239,11 @@ protected: } }; -template <class TCheck = TFakeCheck<>> +template <class TCheck = TFakeCheck<>> class THttpParser: public THttpParserGeneric<0, TCheck> { typedef THttpParserGeneric<0, TCheck> TBaseT; //sorry avoiding gcc 3.4.6 BUG! public: - void Init(THttpHeader* H, bool head_request = false) { + void Init(THttpHeader* H, bool head_request = false) { TBaseT::Header = H; TBaseT::HeaderParser.Init(TBaseT::Header); TBaseT::State = TBaseT::hp_in_header; @@ -251,19 +251,19 @@ public: TBaseT::HeadRequest = head_request; } - void Parse(void* buf, long size) { + void Parse(void* buf, long size) { TBaseT::ParseGeneric(buf, size); } }; class TMemoReader { public: - int Init(void* buf, long bufsize) { + int Init(void* buf, long bufsize) { Buf = buf; Bufsize = bufsize; return 0; } - long Read(void*& buf) { + long Read(void*& buf) { Y_ASSERT(Bufsize >= 0); if (!Bufsize) { Bufsize = -1; @@ -277,15 +277,15 @@ public: protected: long Bufsize; - void* Buf; + void* Buf; }; template <class Reader> class THttpReader: public THttpParserGeneric<1>, public Reader { typedef THttpParserGeneric<1> TBaseT; - + public: - using TBaseT::AssumeConnectionClosed; + using TBaseT::AssumeConnectionClosed; using TBaseT::Header; using TBaseT::ParseGeneric; using TBaseT::State; @@ -299,7 +299,7 @@ public: return parsHeader ? ParseHeader() : SkipHeader(); } - long Read(void*& buf) { + long Read(void*& buf) { long Chunk; do { if (!Size) { @@ -317,7 +317,7 @@ public: if (State == hp_eof) { Size = 0; Eoferr = 0; - } else if (State == hp_error) + } else if (State == hp_error) return Eoferr = -1; } while (!Chunk); return Chunk; @@ -352,9 +352,9 @@ protected: hdrsize -= Size; } State = Header->transfer_chunked ? hp_begin_chunk_header - : Header->content_length == 0 ? hp_eof - : Header->content_length > 0 ? hp_read_alive - : hp_read_closed; + : Header->content_length == 0 ? hp_eof + : Header->content_length > 0 ? hp_read_alive + : hp_read_closed; Header->entity_size = 0; if (State == hp_eof) Eoferr = 0; @@ -366,7 +366,7 @@ protected: return 0; } - void* Ptr; + void* Ptr; long Size; - int Eoferr; + int Eoferr; }; diff --git a/library/cpp/http/fetch/httpparser_ut.cpp b/library/cpp/http/fetch/httpparser_ut.cpp index 6957eb2f5f..3b3b938e7a 100644 --- a/library/cpp/http/fetch/httpparser_ut.cpp +++ b/library/cpp/http/fetch/httpparser_ut.cpp @@ -2,13 +2,13 @@ #include <library/cpp/testing/unittest/registar.h> -#define ENUM_OUT(arg) \ - case type ::arg: { \ - out << #arg; \ - return; \ - } +#define ENUM_OUT(arg) \ + case type ::arg: { \ + out << #arg; \ + return; \ + } -template <> +template <> void Out<THttpParserBase::States>(IOutputStream& out, THttpParserBase::States st) { using type = THttpParserBase::States; switch (st) { @@ -24,27 +24,27 @@ void Out<THttpParserBase::States>(IOutputStream& out, THttpParserBase::States st } namespace { - class TSomethingLikeFakeCheck; + class TSomethingLikeFakeCheck; - using TTestHttpParser = THttpParser<TSomethingLikeFakeCheck>; + using TTestHttpParser = THttpParser<TSomethingLikeFakeCheck>; - class TSomethingLikeFakeCheck { - TString Body_; + class TSomethingLikeFakeCheck { + TString Body_; - public: - const TString& Body() const { - return Body_; - } + public: + const TString& Body() const { + return Body_; + } - // other functions are not really called by THttpParser - void CheckDocPart(const void* buf, size_t len, THttpHeader* /* header */) { - TString s(static_cast<const char*>(buf), len); - Cout << "State = " << static_cast<TTestHttpParser*>(this)->GetState() << ", CheckDocPart(" << s.Quote() << ")\n"; - Body_ += s; - } - }; + // other functions are not really called by THttpParser + void CheckDocPart(const void* buf, size_t len, THttpHeader* /* header */) { + TString s(static_cast<const char*>(buf), len); + Cout << "State = " << static_cast<TTestHttpParser*>(this)->GetState() << ", CheckDocPart(" << s.Quote() << ")\n"; + Body_ += s; + } + }; -} +} Y_UNIT_TEST_SUITE(TestHttpParser) { Y_UNIT_TEST(TestTrivialRequest) { @@ -73,9 +73,9 @@ Y_UNIT_TEST_SUITE(TestHttpParser) { UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof); UNIT_ASSERT_EQUAL(parser.Body(), "OK"); UNIT_ASSERT_EQUAL(hdr.header_size, strlen( - "HTTP/1.1 200 Ok\r\n" - "Content-Length: 2\r\n" - "\r\n")); + "HTTP/1.1 200 Ok\r\n" + "Content-Length: 2\r\n" + "\r\n")); UNIT_ASSERT_EQUAL(hdr.entity_size, strlen("OK")); } @@ -98,36 +98,36 @@ Y_UNIT_TEST_SUITE(TestHttpParser) { UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof); UNIT_ASSERT_EQUAL(parser.Body(), "OkAllRight"); UNIT_ASSERT_EQUAL(hdr.header_size, strlen( - "HTTP/1.1 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n")); + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n")); const int off_by_one_err = -1; // XXX: it really looks so UNIT_ASSERT_EQUAL(hdr.entity_size + off_by_one_err, strlen( - "2\r\n" - "Ok\r\n" - "8\r\n" - "AllRight\r\n" - "0\r\n" - "\r\n")); + "2\r\n" + "Ok\r\n" + "8\r\n" + "AllRight\r\n" + "0\r\n" + "\r\n")); } static const TString PipelineClenBlob_{ - "HTTP/1.1 200 Ok\r\n" - "Content-Length: 4\r\n" - "\r\n" - "OK\r\n" - "HTTP/1.1 200 Zz\r\n" - "Content-Length: 4\r\n" - "\r\n" - "ZZ\r\n"}; - - void AssertPipelineClen(TTestHttpParser & parser, const THttpHeader& hdr) { + "HTTP/1.1 200 Ok\r\n" + "Content-Length: 4\r\n" + "\r\n" + "OK\r\n" + "HTTP/1.1 200 Zz\r\n" + "Content-Length: 4\r\n" + "\r\n" + "ZZ\r\n"}; + + void AssertPipelineClen(TTestHttpParser & parser, const THttpHeader& hdr) { UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof); UNIT_ASSERT_EQUAL(4, hdr.content_length); UNIT_ASSERT_EQUAL(hdr.header_size, strlen( - "HTTP/1.1 200 Ok\r\n" - "Content-Length: 4\r\n" - "\r\n")); + "HTTP/1.1 200 Ok\r\n" + "Content-Length: 4\r\n" + "\r\n")); } Y_UNIT_TEST(TestPipelineClenByteByByte) { @@ -154,55 +154,55 @@ Y_UNIT_TEST_SUITE(TestHttpParser) { parser.Parse((void*)blob.data(), blob.size()); AssertPipelineClen(parser, hdr); UNIT_ASSERT_EQUAL(parser.Body(), - "OK\r\n" - "HTTP/1.1 200 Zz\r\n" - "Content-Length: 4\r\n" - "\r\n" - "ZZ\r\n"); + "OK\r\n" + "HTTP/1.1 200 Zz\r\n" + "Content-Length: 4\r\n" + "\r\n" + "ZZ\r\n"); UNIT_ASSERT_EQUAL(hdr.entity_size, strlen( - "OK\r\n" - "HTTP/1.1 200 Zz\r\n" - "Content-Length: 4\r\n" - "\r\n" - "ZZ\r\n")); + "OK\r\n" + "HTTP/1.1 200 Zz\r\n" + "Content-Length: 4\r\n" + "\r\n" + "ZZ\r\n")); } static const TString PipelineChunkedBlob_{ - "HTTP/1.1 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "2\r\n" - "Ok\r\n" - "8\r\n" - "AllRight\r\n" - "0\r\n" - "\r\n" - "HTTP/1.1 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "2\r\n" - "Yo\r\n" - "8\r\n" - "uWin!Iam\r\n" - "0\r\n" - "\r\n"}; - - void AssertPipelineChunked(TTestHttpParser & parser, const THttpHeader& hdr) { + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "2\r\n" + "Ok\r\n" + "8\r\n" + "AllRight\r\n" + "0\r\n" + "\r\n" + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "2\r\n" + "Yo\r\n" + "8\r\n" + "uWin!Iam\r\n" + "0\r\n" + "\r\n"}; + + void AssertPipelineChunked(TTestHttpParser & parser, const THttpHeader& hdr) { UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof); UNIT_ASSERT_EQUAL(parser.Body(), "OkAllRight"); UNIT_ASSERT_EQUAL(-1, hdr.content_length); UNIT_ASSERT_EQUAL(hdr.header_size, strlen( - "HTTP/1.1 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n")); + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n")); const int off_by_one_err = -1; UNIT_ASSERT_EQUAL(hdr.entity_size + off_by_one_err, strlen( - "2\r\n" - "Ok\r\n" - "8\r\n" - "AllRight\r\n" - "0\r\n" - "\r\n")); + "2\r\n" + "Ok\r\n" + "8\r\n" + "AllRight\r\n" + "0\r\n" + "\r\n")); } Y_UNIT_TEST(TestPipelineChunkedByteByByte) { diff --git a/library/cpp/http/fetch/httpzreader.h b/library/cpp/http/fetch/httpzreader.h index a8df608a9f..68eb00853d 100644 --- a/library/cpp/http/fetch/httpzreader.h +++ b/library/cpp/http/fetch/httpzreader.h @@ -1,26 +1,26 @@ #pragma once -#include "httpheader.h" -#include "httpparser.h" -#include "exthttpcodes.h" +#include "httpheader.h" +#include "httpparser.h" +#include "exthttpcodes.h" #include <util/system/defaults.h> #include <util/generic/yexception.h> #include <contrib/libs/zlib/zlib.h> -#include <errno.h> - +#include <errno.h> + #ifndef ENOTSUP -#define ENOTSUP 45 +#define ENOTSUP 45 #endif template <class Reader> class TCompressedHttpReader: public THttpReader<Reader> { typedef THttpReader<Reader> TBase; - + public: - using TBase::AssumeConnectionClosed; + using TBase::AssumeConnectionClosed; using TBase::Header; using TBase::ParseGeneric; using TBase::State; @@ -78,7 +78,7 @@ public: return ret; } - long Read(void*& buf) { + long Read(void*& buf) { if (!CompressedInput) { long res = TBase::Read(buf); if (res > 0) { @@ -93,7 +93,7 @@ public: while (true) { if (Stream.avail_in == 0) { - void* tmpin = Stream.next_in; + void* tmpin = Stream.next_in; long res = TBase::Read(tmpin); Stream.next_in = (Bytef*)tmpin; if (res <= 0) @@ -121,10 +121,10 @@ public: ZErr = E2BIG; return -1; } - if (!IgnoreTrailingGarbage && BufSize == Stream.avail_out && Stream.avail_in > 0) { + if (!IgnoreTrailingGarbage && BufSize == Stream.avail_out && Stream.avail_in > 0) { Header->error = EXT_HTTP_GZIPERROR; ZErr = EFAULT; - Stream.msg = (char*)"trailing garbage"; + Stream.msg = (char*)"trailing garbage"; return -1; } return long(BufSize - Stream.avail_out); @@ -148,7 +148,7 @@ public: return -1; } - const char* ZMsg() const { + const char* ZMsg() const { return Stream.msg; } @@ -173,7 +173,7 @@ protected: return 0; case HTTP_COMPRESSION_GZIP: CompressedInput = true; - winsize += 16; // 16 indicates gzip, see zlib.h + winsize += 16; // 16 indicates gzip, see zlib.h break; case HTTP_COMPRESSION_DEFLATE: CompressedInput = true; @@ -240,21 +240,21 @@ protected: bool IgnoreTrailingGarbage; }; -class zlib_exception: public yexception { +class zlib_exception: public yexception { }; template <class Reader> class SCompressedHttpReader: public TCompressedHttpReader<Reader> { typedef TCompressedHttpReader<Reader> TBase; - + public: using TBase::ZError; using TBase::ZMsg; SCompressedHttpReader() - : TBase() - { - } + : TBase() + { + } int Init( THttpHeader* H, @@ -268,7 +268,7 @@ public: return (int)HandleRetValue((long)ret); } - long Read(void*& buf) { + long Read(void*& buf) { long ret = TBase::Read(buf); return HandleRetValue(ret); } @@ -281,7 +281,7 @@ protected: case ENOMEM: ythrow yexception() << "SCompressedHttpReader: not enough memory"; case EINVAL: - ythrow yexception() << "SCompressedHttpReader: zlib error: " << ZMsg(); + ythrow yexception() << "SCompressedHttpReader: zlib error: " << ZMsg(); case ENOTSUP: ythrow yexception() << "SCompressedHttpReader: unsupported compression method"; case EFAULT: diff --git a/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h b/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h index d01a5911e7..0df89bdc79 100644 --- a/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h +++ b/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h @@ -1,155 +1,155 @@ #pragma once char hreflang_ut_in[] = "HTTP/1.1 200 OK\n" - "Date: Thu, 15 Nov 2012 22:38:28 GMT\n" - "Server: Apache/2\n" - "X-Powered-By: PHP/5.2.17\n" - "Set-Cookie: PHPSESSID=6d69474d1cc019d7d82714c9472bc6d6; path=/\n" - "Expires: Thu, 19 Nov 1981 08:52:00 GMT\n" - "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\n" - "Pragma: no-cache\n" - "Link: <http://www.forexticket.cn.com/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-CN'\n" - "Link: <http://www.forexticket.tw/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-TW'\n" - "Link: <http://www.forexticket.hk/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-HK'\n" - "Link: <http://www.forexticket.sg/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-SG'\n" - "Link: <http://www.forexticket.in/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-IN'\n" - "Link: <http://www.forexticket.com.fj/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-FJ'\n" - "Link: <http://www.forexticket.in/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-IN'\n" - "Link: <http://www.forexticket.us/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-US'\n" - "Link: <http://www.forexticket.com.pk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PK'\n" - "Link: <http://www.forexticket-bd.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-BD'\n" - "Link: <http://www.forexticket-ng.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NG'\n" - "Link: <http://www.forexticket.co.uk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GB'\n" - "Link: <http://www.forexticket.co.za/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-ZA'\n" - "Link: <http://www.forexticket.co.ke/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KE'\n" - "Link: <http://www.forexticket.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CA'\n" - "Link: <http://www.forexticket-gh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GH'\n" - "Link: <http://www.forexticket.biz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-AU'\n" - "Link: <http://www.forexticket.cm/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CM'\n" - "Link: <http://www.forexticket-kh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KH'\n" - "Link: <http://www.forexticket.hk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-HK'\n" - "Link: <http://www.forexticket.la/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-LA'\n" - "Link: <http://www.forexticket.sg/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-SG'\n" - "Link: <http://www.forexticket.co.nz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NZ'\n" - "Link: <http://www.forexticket.com.pr/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PR'\n" - "Link: <http://www.forexticket.com.fj/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-FJ'\n" - "Link: <http://www.forexticket.us/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-US'\n" - "Link: <http://www.forexticket.mx/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-MX'\n" - "Link: <http://www.forexticket.co/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CO'\n" - "Link: <http://www.forexticket.com.ar/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-AR'\n" - "Link: <http://www.forexticket-pe.com/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PE'\n" - "Link: <http://www.forexticket.co.ve/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-VE'\n" - "Link: <http://www.forexticket.cl/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CL'\n" - "Link: <http://www.forexticket.ec/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-EC'\n" - "Link: <http://www.forexticket.com.gt/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-GT'\n" - "Link: <http://www.forexticket.bo/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-BO'\n" - "Link: <http://www.forexticket.hn/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-HN'\n" - "Link: <http://www.forexticket.com.py/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PY'\n" - "Link: <http://www.forexticket.es/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-ES'\n" - "Link: <http://www.forexticket.com.sv/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-SV'\n" - "Link: <http://www.forexticket.com.ni/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-NI'\n" - "Link: <http://www.forexticket.co.cr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CR'\n" - "Link: <http://www.forexticket.com.pr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PR'\n" - "Link: <http://www.forexticket.com.uy/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-UY'\n" - "Link: <http://www.forexticket.com.pa/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PA'\n" - "Link: <http://www.forexticket.asia.com/id/currency/converter-EEK-XAG>; rel='alternate'; hreflang='id-ID'\n" - "Link: <http://www.forexticket.com.br/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-BR'\n" - "Link: <http://www.forexticket-mz.com/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-MZ'\n" - "Link: <http://www.forexticket.com.pt/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-PT'\n" - "Link: <http://www.forexticket.tl/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-TL'\n" - "Link: <http://www.forexticket.ru/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-RU'\n" - "Link: <http://www.forexticket-kz.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KZ'\n" - "Link: <http://www.forexticket-tj.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-TJ'\n" - "Link: <http://www.forexticket-kg.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KG'\n" - "Link: <http://www.forexticket-ge.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-GE'\n" - "Link: <http://www.forexticket.mn/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-MN'\n" - "Link: <http://www.forexticket.jp/ja/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ja-JP'\n" - "Link: <http://www.forexticket-ph.com/tl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tl-PH'\n" - "Link: <http://www.forexticket.vn/vi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='vi-VN'\n" - "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-DE'\n" - "Link: <http://www.forexticket.be/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-BE'\n" - "Link: <http://www.forexticket.at/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-AT'\n" - "Link: <http://www.forexticket.ch/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-CH'\n" - "Link: <http://www.forexticket.lu/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LU'\n" - "Link: <http://www.forexticket.li/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LI'\n" - "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='canonical'\n" - "Link: <http://www.forexticket-eg.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-EG'\n" - "Link: <http://www.forexticket-dz.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-DZ'\n" - "Link: <http://www.forexticket-ma.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-MA'\n" - "Link: <http://www.forexticket-iq.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IQ'\n" - "Link: <http://www.forexticket-sa.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SA'\n" - "Link: <http://www.forexticket-sy.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SY'\n" - "Link: <http://www.forexticket-tn.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TN'\n" - "Link: <http://www.forexticket-td.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TD'\n" - "Link: <http://www.forexticket-so.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SO'\n" - "Link: <http://www.forexticket.co.il/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IL'\n" - "Link: <http://www.forexticket-jo.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-JO'\n" - "Link: <http://www.forexticket.ae/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-AE'\n" - "Link: <http://www.forexticket-lb.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-LB'\n" - "Link: <http://www.forexticket-om.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-OM'\n" - "Link: <http://www.forexticket-kw.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-KW'\n" - "Link: <http://www.forexticket-tr.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-TR'\n" - "Link: <http://www.forexticket-bg.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-BG'\n" - "Link: <http://www.forexticket-cy.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-CY'\n" - "Link: <http://www.forexticket.ir/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-IR'\n" - "Link: <http://www.forexticket.af/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-AF'\n" - "Link: <http://www.forexticket.cd/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CD'\n" - "Link: <http://www.forexticket.fr/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-FR'\n" - "Link: <http://www.forexticket.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CA'\n" - "Link: <http://www.forexticket.mg/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-MG'\n" - "Link: <http://www.forexticket.cm/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CM'\n" - "Link: <http://www.forexticket-kh.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-KH'\n" - "Link: <http://www.forexticket-ml.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-ML'\n" - "Link: <http://www.forexticket-sn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-SN'\n" - "Link: <http://www.forexticket-tn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TN'\n" - "Link: <http://www.forexticket-td.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TD'\n" - "Link: <http://www.forexticket.be/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-BE'\n" - "Link: <http://www.forexticket-gn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-GN'\n" - "Link: <http://www.forexticket.ht/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-HT'\n" - "Link: <http://www.forexticket.ch/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CH'\n" - "Link: <http://www.forexticket.la/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LA'\n" - "Link: <http://www.forexticket.lu/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LU'\n" - "Link: <http://www.forexticket-th.com/th/currency/converter-EEK-XAG>; rel='alternate'; hreflang='th-TH'\n" - "Link: <http://www.forexticket.co.uk/cy/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cy-GB'\n" - "Link: <http://www.forexticket.co.uk/ga/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ga-GB'\n" - "Link: <http://www.forexticket.it/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-IT'\n" - "Link: <http://www.forexticket.ch/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-CH'\n" - "Link: <http://www.forexticket.co.za/af/currency/converter-EEK-XAG>; rel='alternate'; hreflang='af-ZA'\n" - "Link: <http://www.forexticket.kr/ko/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ko-KR'\n" - "Link: <http://www.forexticket-ua.com/uk/currency/converter-EEK-XAG>; rel='alternate'; hreflang='uk-UA'\n" - "Link: <http://www.forexticket-tz.com/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-TZ'\n" - "Link: <http://www.forexticket.co.ke/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-KE'\n" - "Link: <http://www.forexticket.pl/pl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='pl-PL'\n" - "Link: <http://www.forexticket.com.my/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-MY'\n" - "Link: <http://www.forexticket.sg/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-SG'\n" - "Link: <http://www.forexticket.ro/ro/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ro-RO'\n" - "Link: <http://www.forexticket.nl/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-NL'\n" - "Link: <http://www.forexticket.be/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-BE'\n" - "Link: <http://www.forexticket.gr/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-GR'\n" - "Link: <http://www.forexticket-al.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-AL'\n" - "Link: <http://www.forexticket-cy.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-CY'\n" - "Link: <http://www.forexticket.cz/cs/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cs-CZ'\n" - "Link: <http://www.forexticket.hu/hu/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hu-HU'\n" - "Link: <http://www.forexticket.se/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-SE'\n" - "Link: <http://www.forexticket.eu/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-FI'\n" - "Link: <http://www.forexticket.co.il/iw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='iw-IL'\n" - "Link: <http://www.forexticket.co.il/yi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='yi-IL'\n" - "Link: <http://www.forexticket-bg.com/bg/currency/converter-EEK-XAG>; rel='alternate'; hreflang='bg-BG'\n" - "Link: <http://www.forexticket.es/ca/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ca-ES'\n" - "Link: <http://www.forexticket.es/gl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='gl-ES'\n" - "Link: <http://www.forexticket.dk/da/currency/converter-EEK-XAG>; rel='alternate'; hreflang='da-DK'\n" - "Link: <http://www.forexticket.eu/fi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fi-FI'\n" - "Link: <http://www.forexticket-hr.com/hr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hr-HR'\n" - "Link: <http://www.forexticket-hr.com/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-HR'\n" - "Link: <http://www.forexticket.me/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-ME'\n" - "Link: <http://www.forexticket.lt/lt/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lt-LT'\n" - "Link: <http://www.forexticket-al.com/sq/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sq-AL'\n" - "Link: <http://www.forexticket.lv/lv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lv-LV'\n" - "Link: <http://www.forexticket.co.ee/et/currency/converter-EEK-XAG>; rel='alternate'; hreflang='et-EE'\n" - "Vary: Accept-Encoding,User-Agent\n" - "Content-Encoding: gzip\n" - "Keep-Alive: timeout=1, max=100\n" - "Connection: Keep-Alive\n" - "Transfer-Encoding: chunked\n" - "Content-Type: text/html\n" - "\n"; + "Date: Thu, 15 Nov 2012 22:38:28 GMT\n" + "Server: Apache/2\n" + "X-Powered-By: PHP/5.2.17\n" + "Set-Cookie: PHPSESSID=6d69474d1cc019d7d82714c9472bc6d6; path=/\n" + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\n" + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\n" + "Pragma: no-cache\n" + "Link: <http://www.forexticket.cn.com/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-CN'\n" + "Link: <http://www.forexticket.tw/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-TW'\n" + "Link: <http://www.forexticket.hk/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-HK'\n" + "Link: <http://www.forexticket.sg/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-SG'\n" + "Link: <http://www.forexticket.in/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-IN'\n" + "Link: <http://www.forexticket.com.fj/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-FJ'\n" + "Link: <http://www.forexticket.in/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-IN'\n" + "Link: <http://www.forexticket.us/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-US'\n" + "Link: <http://www.forexticket.com.pk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PK'\n" + "Link: <http://www.forexticket-bd.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-BD'\n" + "Link: <http://www.forexticket-ng.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NG'\n" + "Link: <http://www.forexticket.co.uk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GB'\n" + "Link: <http://www.forexticket.co.za/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-ZA'\n" + "Link: <http://www.forexticket.co.ke/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KE'\n" + "Link: <http://www.forexticket.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CA'\n" + "Link: <http://www.forexticket-gh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GH'\n" + "Link: <http://www.forexticket.biz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-AU'\n" + "Link: <http://www.forexticket.cm/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CM'\n" + "Link: <http://www.forexticket-kh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KH'\n" + "Link: <http://www.forexticket.hk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-HK'\n" + "Link: <http://www.forexticket.la/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-LA'\n" + "Link: <http://www.forexticket.sg/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-SG'\n" + "Link: <http://www.forexticket.co.nz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NZ'\n" + "Link: <http://www.forexticket.com.pr/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PR'\n" + "Link: <http://www.forexticket.com.fj/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-FJ'\n" + "Link: <http://www.forexticket.us/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-US'\n" + "Link: <http://www.forexticket.mx/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-MX'\n" + "Link: <http://www.forexticket.co/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CO'\n" + "Link: <http://www.forexticket.com.ar/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-AR'\n" + "Link: <http://www.forexticket-pe.com/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PE'\n" + "Link: <http://www.forexticket.co.ve/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-VE'\n" + "Link: <http://www.forexticket.cl/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CL'\n" + "Link: <http://www.forexticket.ec/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-EC'\n" + "Link: <http://www.forexticket.com.gt/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-GT'\n" + "Link: <http://www.forexticket.bo/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-BO'\n" + "Link: <http://www.forexticket.hn/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-HN'\n" + "Link: <http://www.forexticket.com.py/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PY'\n" + "Link: <http://www.forexticket.es/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-ES'\n" + "Link: <http://www.forexticket.com.sv/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-SV'\n" + "Link: <http://www.forexticket.com.ni/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-NI'\n" + "Link: <http://www.forexticket.co.cr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CR'\n" + "Link: <http://www.forexticket.com.pr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PR'\n" + "Link: <http://www.forexticket.com.uy/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-UY'\n" + "Link: <http://www.forexticket.com.pa/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PA'\n" + "Link: <http://www.forexticket.asia.com/id/currency/converter-EEK-XAG>; rel='alternate'; hreflang='id-ID'\n" + "Link: <http://www.forexticket.com.br/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-BR'\n" + "Link: <http://www.forexticket-mz.com/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-MZ'\n" + "Link: <http://www.forexticket.com.pt/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-PT'\n" + "Link: <http://www.forexticket.tl/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-TL'\n" + "Link: <http://www.forexticket.ru/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-RU'\n" + "Link: <http://www.forexticket-kz.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KZ'\n" + "Link: <http://www.forexticket-tj.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-TJ'\n" + "Link: <http://www.forexticket-kg.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KG'\n" + "Link: <http://www.forexticket-ge.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-GE'\n" + "Link: <http://www.forexticket.mn/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-MN'\n" + "Link: <http://www.forexticket.jp/ja/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ja-JP'\n" + "Link: <http://www.forexticket-ph.com/tl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tl-PH'\n" + "Link: <http://www.forexticket.vn/vi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='vi-VN'\n" + "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-DE'\n" + "Link: <http://www.forexticket.be/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-BE'\n" + "Link: <http://www.forexticket.at/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-AT'\n" + "Link: <http://www.forexticket.ch/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-CH'\n" + "Link: <http://www.forexticket.lu/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LU'\n" + "Link: <http://www.forexticket.li/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LI'\n" + "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='canonical'\n" + "Link: <http://www.forexticket-eg.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-EG'\n" + "Link: <http://www.forexticket-dz.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-DZ'\n" + "Link: <http://www.forexticket-ma.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-MA'\n" + "Link: <http://www.forexticket-iq.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IQ'\n" + "Link: <http://www.forexticket-sa.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SA'\n" + "Link: <http://www.forexticket-sy.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SY'\n" + "Link: <http://www.forexticket-tn.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TN'\n" + "Link: <http://www.forexticket-td.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TD'\n" + "Link: <http://www.forexticket-so.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SO'\n" + "Link: <http://www.forexticket.co.il/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IL'\n" + "Link: <http://www.forexticket-jo.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-JO'\n" + "Link: <http://www.forexticket.ae/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-AE'\n" + "Link: <http://www.forexticket-lb.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-LB'\n" + "Link: <http://www.forexticket-om.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-OM'\n" + "Link: <http://www.forexticket-kw.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-KW'\n" + "Link: <http://www.forexticket-tr.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-TR'\n" + "Link: <http://www.forexticket-bg.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-BG'\n" + "Link: <http://www.forexticket-cy.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-CY'\n" + "Link: <http://www.forexticket.ir/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-IR'\n" + "Link: <http://www.forexticket.af/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-AF'\n" + "Link: <http://www.forexticket.cd/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CD'\n" + "Link: <http://www.forexticket.fr/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-FR'\n" + "Link: <http://www.forexticket.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CA'\n" + "Link: <http://www.forexticket.mg/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-MG'\n" + "Link: <http://www.forexticket.cm/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CM'\n" + "Link: <http://www.forexticket-kh.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-KH'\n" + "Link: <http://www.forexticket-ml.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-ML'\n" + "Link: <http://www.forexticket-sn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-SN'\n" + "Link: <http://www.forexticket-tn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TN'\n" + "Link: <http://www.forexticket-td.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TD'\n" + "Link: <http://www.forexticket.be/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-BE'\n" + "Link: <http://www.forexticket-gn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-GN'\n" + "Link: <http://www.forexticket.ht/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-HT'\n" + "Link: <http://www.forexticket.ch/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CH'\n" + "Link: <http://www.forexticket.la/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LA'\n" + "Link: <http://www.forexticket.lu/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LU'\n" + "Link: <http://www.forexticket-th.com/th/currency/converter-EEK-XAG>; rel='alternate'; hreflang='th-TH'\n" + "Link: <http://www.forexticket.co.uk/cy/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cy-GB'\n" + "Link: <http://www.forexticket.co.uk/ga/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ga-GB'\n" + "Link: <http://www.forexticket.it/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-IT'\n" + "Link: <http://www.forexticket.ch/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-CH'\n" + "Link: <http://www.forexticket.co.za/af/currency/converter-EEK-XAG>; rel='alternate'; hreflang='af-ZA'\n" + "Link: <http://www.forexticket.kr/ko/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ko-KR'\n" + "Link: <http://www.forexticket-ua.com/uk/currency/converter-EEK-XAG>; rel='alternate'; hreflang='uk-UA'\n" + "Link: <http://www.forexticket-tz.com/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-TZ'\n" + "Link: <http://www.forexticket.co.ke/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-KE'\n" + "Link: <http://www.forexticket.pl/pl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='pl-PL'\n" + "Link: <http://www.forexticket.com.my/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-MY'\n" + "Link: <http://www.forexticket.sg/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-SG'\n" + "Link: <http://www.forexticket.ro/ro/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ro-RO'\n" + "Link: <http://www.forexticket.nl/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-NL'\n" + "Link: <http://www.forexticket.be/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-BE'\n" + "Link: <http://www.forexticket.gr/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-GR'\n" + "Link: <http://www.forexticket-al.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-AL'\n" + "Link: <http://www.forexticket-cy.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-CY'\n" + "Link: <http://www.forexticket.cz/cs/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cs-CZ'\n" + "Link: <http://www.forexticket.hu/hu/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hu-HU'\n" + "Link: <http://www.forexticket.se/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-SE'\n" + "Link: <http://www.forexticket.eu/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-FI'\n" + "Link: <http://www.forexticket.co.il/iw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='iw-IL'\n" + "Link: <http://www.forexticket.co.il/yi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='yi-IL'\n" + "Link: <http://www.forexticket-bg.com/bg/currency/converter-EEK-XAG>; rel='alternate'; hreflang='bg-BG'\n" + "Link: <http://www.forexticket.es/ca/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ca-ES'\n" + "Link: <http://www.forexticket.es/gl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='gl-ES'\n" + "Link: <http://www.forexticket.dk/da/currency/converter-EEK-XAG>; rel='alternate'; hreflang='da-DK'\n" + "Link: <http://www.forexticket.eu/fi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fi-FI'\n" + "Link: <http://www.forexticket-hr.com/hr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hr-HR'\n" + "Link: <http://www.forexticket-hr.com/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-HR'\n" + "Link: <http://www.forexticket.me/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-ME'\n" + "Link: <http://www.forexticket.lt/lt/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lt-LT'\n" + "Link: <http://www.forexticket-al.com/sq/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sq-AL'\n" + "Link: <http://www.forexticket.lv/lv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lv-LV'\n" + "Link: <http://www.forexticket.co.ee/et/currency/converter-EEK-XAG>; rel='alternate'; hreflang='et-EE'\n" + "Vary: Accept-Encoding,User-Agent\n" + "Content-Encoding: gzip\n" + "Keep-Alive: timeout=1, max=100\n" + "Connection: Keep-Alive\n" + "Transfer-Encoding: chunked\n" + "Content-Type: text/html\n" + "\n"; diff --git a/library/cpp/http/fetch/ya.make b/library/cpp/http/fetch/ya.make index 9962b82ee1..7737127463 100644 --- a/library/cpp/http/fetch/ya.make +++ b/library/cpp/http/fetch/ya.make @@ -1,19 +1,19 @@ -LIBRARY() +LIBRARY() OWNER( g:zora ) -PEERDIR( - contrib/libs/zlib +PEERDIR( + contrib/libs/zlib library/cpp/charset library/cpp/digest/md5 library/cpp/http/misc library/cpp/logger library/cpp/mime/types library/cpp/uri -) - +) + SRCS( http_digest.cpp http_socket.cpp @@ -32,7 +32,7 @@ SRCS( GENERATE_ENUM_SERIALIZATION(httpheader.h) SET(RAGEL6_FLAGS -CF1) - + END() RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/http/io/chunk.cpp b/library/cpp/http/io/chunk.cpp index 80a423e7c9..6975d9eac1 100644 --- a/library/cpp/http/io/chunk.cpp +++ b/library/cpp/http/io/chunk.cpp @@ -1,70 +1,70 @@ -#include "chunk.h" - +#include "chunk.h" + #include "headers.h" -#include <util/string/cast.h> -#include <util/generic/utility.h> -#include <util/generic/yexception.h> - +#include <util/string/cast.h> +#include <util/generic/utility.h> +#include <util/generic/yexception.h> + static inline size_t ParseHex(const TString& s) { - if (s.empty()) { + if (s.empty()) { ythrow yexception() << "can not parse chunk length(empty string)"; - } - - size_t ret = 0; - + } + + size_t ret = 0; + for (TString::const_iterator c = s.begin(); c != s.end(); ++c) { - const char ch = *c; - - if (ch >= '0' && ch <= '9') { - ret *= 16; - ret += ch - '0'; - } else if (ch >= 'a' && ch <= 'f') { - ret *= 16; - ret += 10 + ch - 'a'; - } else if (ch >= 'A' && ch <= 'F') { - ret *= 16; - ret += 10 + ch - 'A'; - } else if (ch == ';') { - break; - } else if (isspace(ch)) { - continue; - } else { + const char ch = *c; + + if (ch >= '0' && ch <= '9') { + ret *= 16; + ret += ch - '0'; + } else if (ch >= 'a' && ch <= 'f') { + ret *= 16; + ret += 10 + ch - 'a'; + } else if (ch >= 'A' && ch <= 'F') { + ret *= 16; + ret += 10 + ch - 'A'; + } else if (ch == ';') { + break; + } else if (isspace(ch)) { + continue; + } else { ythrow yexception() << "can not parse chunk length(" << s.data() << ")"; - } - } - - return ret; -} - -static inline char* ToHex(size_t len, char* buf) { - do { - const size_t val = len % 16; - - *--buf = (val < 10) ? (val + '0') : (val - 10 + 'a'); - len /= 16; - } while (len); - - return buf; -} - -class TChunkedInput::TImpl { -public: + } + } + + return ret; +} + +static inline char* ToHex(size_t len, char* buf) { + do { + const size_t val = len % 16; + + *--buf = (val < 10) ? (val + '0') : (val - 10 + 'a'); + len /= 16; + } while (len); + + return buf; +} + +class TChunkedInput::TImpl { +public: inline TImpl(IInputStream* slave, TMaybe<THttpHeaders>* trailers) - : Slave_(slave) + : Slave_(slave) , Trailers_(trailers) - , Pending_(0) - , LastChunkReaded_(false) - { + , Pending_(0) + , LastChunkReaded_(false) + { if (Trailers_) { Trailers_->Clear(); } - } - + } + inline ~TImpl() { - } - - inline size_t Read(void* buf, size_t len) { + } + + inline size_t Read(void* buf, size_t len) { return Perform(len, [this, buf](size_t toRead) { return Slave_->Read(buf, toRead); }); } @@ -73,174 +73,174 @@ public: } private: - template <class Operation> + template <class Operation> inline size_t Perform(size_t len, const Operation& operation) { - if (!HavePendingData()) { - return 0; - } - + if (!HavePendingData()) { + return 0; + } + const size_t toProcess = Min(Pending_, len); - + if (toProcess) { const size_t processed = operation(toProcess); - + if (!processed) { - ythrow yexception() << "malformed http chunk"; - } - + ythrow yexception() << "malformed http chunk"; + } + Pending_ -= processed; - + return processed; - } - - return 0; - } - - inline bool HavePendingData() { - if (LastChunkReaded_) { - return false; - } - - if (!Pending_) { - if (!ProceedToNextChunk()) { - return false; - } - } - - return true; - } - - inline bool ProceedToNextChunk() { + } + + return 0; + } + + inline bool HavePendingData() { + if (LastChunkReaded_) { + return false; + } + + if (!Pending_) { + if (!ProceedToNextChunk()) { + return false; + } + } + + return true; + } + + inline bool ProceedToNextChunk() { TString len(Slave_->ReadLine()); - - if (len.empty()) { - /* - * skip crlf from previous chunk - */ - - len = Slave_->ReadLine(); - } - - Pending_ = ParseHex(len); - - if (Pending_) { - return true; - } - + + if (len.empty()) { + /* + * skip crlf from previous chunk + */ + + len = Slave_->ReadLine(); + } + + Pending_ = ParseHex(len); + + if (Pending_) { + return true; + } + if (Trailers_) { Trailers_->ConstructInPlace(Slave_); } - LastChunkReaded_ = true; - - return false; - } - -private: + LastChunkReaded_ = true; + + return false; + } + +private: IInputStream* Slave_; TMaybe<THttpHeaders>* Trailers_; - size_t Pending_; - bool LastChunkReaded_; -}; - + size_t Pending_; + bool LastChunkReaded_; +}; + TChunkedInput::TChunkedInput(IInputStream* slave, TMaybe<THttpHeaders>* trailers) : Impl_(new TImpl(slave, trailers)) -{ -} - +{ +} + TChunkedInput::~TChunkedInput() { -} - -size_t TChunkedInput::DoRead(void* buf, size_t len) { - return Impl_->Read(buf, len); -} - +} + +size_t TChunkedInput::DoRead(void* buf, size_t len) { + return Impl_->Read(buf, len); +} + size_t TChunkedInput::DoSkip(size_t len) { return Impl_->Skip(len); } -class TChunkedOutput::TImpl { +class TChunkedOutput::TImpl { typedef IOutputStream::TPart TPart; - -public: + +public: inline TImpl(IOutputStream* slave) - : Slave_(slave) - { - } - + : Slave_(slave) + { + } + inline ~TImpl() { - } - - inline void Write(const void* buf, size_t len) { - const char* ptr = (const char*)buf; - - while (len) { - const size_t portion = Min<size_t>(len, 1024 * 16); - - WriteImpl(ptr, portion); - - ptr += portion; - len -= portion; - } - } - - inline void WriteImpl(const void* buf, size_t len) { - char tmp[32]; - char* e = tmp + sizeof(tmp); - char* b = ToHex(len, e); - - const TPart parts[] = { - TPart(b, e - b), - TPart::CrLf(), - TPart(buf, len), - TPart::CrLf(), - }; - - Slave_->Write(parts, sizeof(parts) / sizeof(*parts)); - } - - inline void Flush() { - Slave_->Flush(); - } - - inline void Finish() { - Slave_->Write("0\r\n\r\n", 5); - - Flush(); - } - -private: + } + + inline void Write(const void* buf, size_t len) { + const char* ptr = (const char*)buf; + + while (len) { + const size_t portion = Min<size_t>(len, 1024 * 16); + + WriteImpl(ptr, portion); + + ptr += portion; + len -= portion; + } + } + + inline void WriteImpl(const void* buf, size_t len) { + char tmp[32]; + char* e = tmp + sizeof(tmp); + char* b = ToHex(len, e); + + const TPart parts[] = { + TPart(b, e - b), + TPart::CrLf(), + TPart(buf, len), + TPart::CrLf(), + }; + + Slave_->Write(parts, sizeof(parts) / sizeof(*parts)); + } + + inline void Flush() { + Slave_->Flush(); + } + + inline void Finish() { + Slave_->Write("0\r\n\r\n", 5); + + Flush(); + } + +private: IOutputStream* Slave_; -}; - +}; + TChunkedOutput::TChunkedOutput(IOutputStream* slave) - : Impl_(new TImpl(slave)) -{ -} - + : Impl_(new TImpl(slave)) +{ +} + TChunkedOutput::~TChunkedOutput() { - try { - Finish(); - } catch (...) { - } -} - -void TChunkedOutput::DoWrite(const void* buf, size_t len) { - if (Impl_.Get()) { - Impl_->Write(buf, len); - } else { + try { + Finish(); + } catch (...) { + } +} + +void TChunkedOutput::DoWrite(const void* buf, size_t len) { + if (Impl_.Get()) { + Impl_->Write(buf, len); + } else { ythrow yexception() << "can not write to finished stream"; - } -} - -void TChunkedOutput::DoFlush() { - if (Impl_.Get()) { - Impl_->Flush(); - } -} - -void TChunkedOutput::DoFinish() { - if (Impl_.Get()) { - Impl_->Finish(); - Impl_.Destroy(); - } -} + } +} + +void TChunkedOutput::DoFlush() { + if (Impl_.Get()) { + Impl_->Flush(); + } +} + +void TChunkedOutput::DoFinish() { + if (Impl_.Get()) { + Impl_->Finish(); + Impl_.Destroy(); + } +} diff --git a/library/cpp/http/io/chunk.h b/library/cpp/http/io/chunk.h index a77f1b1a9d..88d89fafda 100644 --- a/library/cpp/http/io/chunk.h +++ b/library/cpp/http/io/chunk.h @@ -1,9 +1,9 @@ #pragma once - + #include <util/stream/output.h> #include <util/generic/maybe.h> #include <util/generic/ptr.h> - + class THttpHeaders; /// @addtogroup Streams_Chunked @@ -12,36 +12,36 @@ class THttpHeaders; /// @details Последовательное чтение блоков данных. Предполагается, что /// данные записаны в виде <длина блока><блок данных>. class TChunkedInput: public IInputStream { -public: +public: /// Если передан указатель на trailers, то туда будут записаны HTTP trailer'ы (возможно пустые), /// которые идут после чанков. TChunkedInput(IInputStream* slave, TMaybe<THttpHeaders>* trailers = nullptr); ~TChunkedInput() override; - -private: + +private: size_t DoRead(void* buf, size_t len) override; size_t DoSkip(size_t len) override; - -private: - class TImpl; - THolder<TImpl> Impl_; -}; - + +private: + class TImpl; + THolder<TImpl> Impl_; +}; + /// Вывод данных порциями. /// @details Вывод данных блоками в виде <длина блока><блок данных>. Если объем /// данных превышает 64K, они записываются в виде n блоков по 64K + то, что осталось. class TChunkedOutput: public IOutputStream { -public: +public: TChunkedOutput(IOutputStream* slave); ~TChunkedOutput() override; - -private: + +private: void DoWrite(const void* buf, size_t len) override; void DoFlush() override; void DoFinish() override; - -private: - class TImpl; - THolder<TImpl> Impl_; -}; + +private: + class TImpl; + THolder<TImpl> Impl_; +}; /// @} diff --git a/library/cpp/http/io/chunk_ut.cpp b/library/cpp/http/io/chunk_ut.cpp index 82f9c90b74..da283f8568 100644 --- a/library/cpp/http/io/chunk_ut.cpp +++ b/library/cpp/http/io/chunk_ut.cpp @@ -1,16 +1,16 @@ -#include "chunk.h" - +#include "chunk.h" + #include <library/cpp/testing/unittest/registar.h> - + #include <util/stream/file.h> -#include <util/system/tempfile.h> +#include <util/system/tempfile.h> #include <util/stream/null.h> - -#define CDATA "./chunkedio" - + +#define CDATA "./chunkedio" + Y_UNIT_TEST_SUITE(TestChunkedIO) { - static const char test_data[] = "87s6cfbsudg cuisg s igasidftasiy tfrcua6s"; - + static const char test_data[] = "87s6cfbsudg cuisg s igasidftasiy tfrcua6s"; + TString CombString(const TString& s, size_t chunkSize) { TString result; for (size_t pos = 0; pos < s.size(); pos += 2 * chunkSize) @@ -58,48 +58,48 @@ Y_UNIT_TEST_SUITE(TestChunkedIO) { } Y_UNIT_TEST(TestChunkedIo) { - TTempFile tmpFile(CDATA); + TTempFile tmpFile(CDATA); TString tmp; - - { + + { TUnbufferedFileOutput fo(CDATA); - TChunkedOutput co(&fo); + TChunkedOutput co(&fo); WriteTestData(&co, &tmp); } - + { TUnbufferedFileInput fi(CDATA); TChunkedInput ci(&fi); TString r; - + ReadInSmallChunks(&ci, &r); UNIT_ASSERT_EQUAL(r, tmp); - } - - { + } + + { TUnbufferedFileInput fi(CDATA); - TChunkedInput ci(&fi); + TChunkedInput ci(&fi); TString r; - + ReadCombed(&ci, &r, 11); - + UNIT_ASSERT_EQUAL(r, CombString(tmp, 11)); - } - } - + } + } + Y_UNIT_TEST(TestBadChunk) { - bool hasError = false; - - try { + bool hasError = false; + + try { TString badChunk = "10\r\nqwerty"; TMemoryInput mi(badChunk.data(), badChunk.size()); - TChunkedInput ci(&mi); - TransferData(&ci, &Cnull); - } catch (...) { - hasError = true; - } - - UNIT_ASSERT(hasError); - } -} + TChunkedInput ci(&mi); + TransferData(&ci, &Cnull); + } catch (...) { + hasError = true; + } + + UNIT_ASSERT(hasError); + } +} diff --git a/library/cpp/http/io/compression.cpp b/library/cpp/http/io/compression.cpp index 0c922ad566..8fa1f62ae6 100644 --- a/library/cpp/http/io/compression.cpp +++ b/library/cpp/http/io/compression.cpp @@ -1,66 +1,66 @@ #include "compression.h" - -#if defined(ENABLE_GPL) + +#if defined(ENABLE_GPL) #include <library/cpp/streams/lz/lz.h> -#endif - +#endif + #include <library/cpp/streams/brotli/brotli.h> #include <library/cpp/streams/lzma/lzma.h> #include <library/cpp/streams/bzip2/bzip2.h> - + #include <library/cpp/blockcodecs/stream.h> #include <library/cpp/blockcodecs/codecs.h> - -#include <util/stream/zlib.h> - - + +#include <util/stream/zlib.h> + + TCompressionCodecFactory::TCompressionCodecFactory() { auto gzip = [](auto s) { return MakeHolder<TZLibDecompress>(s); - }; - + }; + Add("gzip", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::GZip); }); Add("deflate", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::ZLib); }); Add("br", [](auto s) { return MakeHolder<TBrotliDecompress>(s); }, [](auto s) { return MakeHolder<TBrotliCompress>(s, 4); }); Add("x-gzip", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::GZip); }); Add("x-deflate", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::ZLib); }); - -#if defined(ENABLE_GPL) + +#if defined(ENABLE_GPL) const ui16 bs = 32 * 1024; - + Add("y-lzo", [](auto s) { return MakeHolder<TLzoDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzoCompress> >(s, bs); }); Add("y-lzf", [](auto s) { return MakeHolder<TLzfDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzfCompress> >(s, bs); }); Add("y-lzq", [](auto s) { return MakeHolder<TLzqDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzqCompress> >(s, bs); }); -#endif - +#endif + Add("y-bzip2", [](auto s) { return MakeHolder<TBZipDecompress>(s); }, [](auto s) { return MakeHolder<TBZipCompress>(s); }); Add("y-lzma", [](auto s) { return MakeHolder<TLzmaDecompress>(s); }, [](auto s) { return MakeHolder<TLzmaCompress>(s); }); - + for (auto codecName : NBlockCodecs::ListAllCodecs()) { if (codecName.StartsWith("zstd06")) { continue; - } - + } + if (codecName.StartsWith("zstd08")) { continue; - } - + } + auto codec = NBlockCodecs::Codec(codecName); - + auto enc = [codec](auto s) { return MakeHolder<NBlockCodecs::TCodedOutput>(s, codec, 32 * 1024); }; - + auto dec = [codec](auto s) { return MakeHolder<NBlockCodecs::TDecodedInput>(s, codec); - }; - + }; + Add(TString("z-") + codecName, dec, enc); - } -} - + } +} + void TCompressionCodecFactory::Add(TStringBuf name, TDecoderConstructor d, TEncoderConstructor e) { Strings_.emplace_back(name); Codecs_[Strings_.back()] = TCodec{d, e}; BestCodecs_.emplace_back(Strings_.back()); -} +} diff --git a/library/cpp/http/io/compression.h b/library/cpp/http/io/compression.h index b566bbb796..f16c4a18eb 100644 --- a/library/cpp/http/io/compression.h +++ b/library/cpp/http/io/compression.h @@ -1,17 +1,17 @@ #pragma once - + #include "stream.h" - + #include <util/generic/deque.h> #include <util/generic/hash.h> - + class TCompressionCodecFactory { -public: +public: using TDecoderConstructor = std::function<THolder<IInputStream>(IInputStream*)>; using TEncoderConstructor = std::function<THolder<IOutputStream>(IOutputStream*)>; - + TCompressionCodecFactory(); - + static inline TCompressionCodecFactory& Instance() noexcept { return *SingletonWithPriority<TCompressionCodecFactory, 0>(); } @@ -20,10 +20,10 @@ public: if (auto codec = Codecs_.FindPtr(name)) { return &codec->Decoder; } - + return nullptr; } - + inline const TEncoderConstructor* FindEncoder(TStringBuf name) const { if (auto codec = Codecs_.FindPtr(name)) { return &codec->Encoder; @@ -31,23 +31,23 @@ public: return nullptr; } - + inline TArrayRef<const TStringBuf> GetBestCodecs() const { return BestCodecs_; } -private: +private: void Add(TStringBuf name, TDecoderConstructor d, TEncoderConstructor e); - + struct TCodec { TDecoderConstructor Decoder; TEncoderConstructor Encoder; }; - + TDeque<TString> Strings_; THashMap<TStringBuf, TCodec> Codecs_; TVector<TStringBuf> BestCodecs_; -}; +}; namespace NHttp { template <typename F> diff --git a/library/cpp/http/io/compression_ut.cpp b/library/cpp/http/io/compression_ut.cpp index 04a3f85689..2f3d131f8c 100644 --- a/library/cpp/http/io/compression_ut.cpp +++ b/library/cpp/http/io/compression_ut.cpp @@ -1,34 +1,34 @@ -#include "stream.h" +#include "stream.h" #include "compression.h" - + #include <library/cpp/testing/unittest/registar.h> #include <library/cpp/testing/unittest/tests_data.h> - -#include <util/stream/zlib.h> + +#include <util/stream/zlib.h> #include <util/generic/hash_set.h> - + Y_UNIT_TEST_SUITE(THttpCompressionTest) { static const TString DATA = "I'm a teapot"; Y_UNIT_TEST(TestGetBestCodecs) { UNIT_ASSERT(TCompressionCodecFactory::Instance().GetBestCodecs().size() > 0); - } + } Y_UNIT_TEST(TestEncoder) { TStringStream buffer; - { + { auto encoder = TCompressionCodecFactory::Instance().FindEncoder("gzip"); UNIT_ASSERT(encoder); - + auto encodedStream = (*encoder)(&buffer); encodedStream->Write(DATA); - } + } TZLibDecompress decompressor(&buffer); UNIT_ASSERT_EQUAL(decompressor.ReadAll(), DATA); } - + Y_UNIT_TEST(TestDecoder) { TStringStream buffer; diff --git a/library/cpp/http/io/fuzz/main.cpp b/library/cpp/http/io/fuzz/main.cpp index 60bc30848f..8ded9c7e32 100644 --- a/library/cpp/http/io/fuzz/main.cpp +++ b/library/cpp/http/io/fuzz/main.cpp @@ -1,15 +1,15 @@ #include <library/cpp/http/io/stream.h> - -#include <util/generic/vector.h> -#include <util/stream/mem.h> - -extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) { - TMemoryInput mi(data, size); - - try { - THttpInput(&mi).ReadAll(); - } catch (...) { - } - - return 0; // Non-zero return values are reserved for future use. -} + +#include <util/generic/vector.h> +#include <util/stream/mem.h> + +extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) { + TMemoryInput mi(data, size); + + try { + THttpInput(&mi).ReadAll(); + } catch (...) { + } + + return 0; // Non-zero return values are reserved for future use. +} diff --git a/library/cpp/http/io/fuzz/ya.make b/library/cpp/http/io/fuzz/ya.make index 2057830af1..8b3ccb1969 100644 --- a/library/cpp/http/io/fuzz/ya.make +++ b/library/cpp/http/io/fuzz/ya.make @@ -1,18 +1,18 @@ FUZZ() - + OWNER( pg g:util ) - -PEERDIR( + +PEERDIR( library/cpp/http/io -) - +) + SIZE(MEDIUM) -SRCS( - main.cpp -) - -END() +SRCS( + main.cpp +) + +END() diff --git a/library/cpp/http/io/headers.cpp b/library/cpp/http/io/headers.cpp index 5d0d4f895d..4ec27a29e8 100644 --- a/library/cpp/http/io/headers.cpp +++ b/library/cpp/http/io/headers.cpp @@ -1,64 +1,64 @@ -#include "headers.h" -#include "stream.h" - +#include "headers.h" +#include "stream.h" + #include <util/generic/strbuf.h> -#include <util/generic/yexception.h> +#include <util/generic/yexception.h> #include <util/stream/output.h> #include <util/string/ascii.h> -#include <util/string/cast.h> -#include <util/string/strip.h> - +#include <util/string/cast.h> +#include <util/string/strip.h> + static inline TStringBuf Trim(const char* b, const char* e) noexcept { - return StripString(TStringBuf(b, e)); -} - + return StripString(TStringBuf(b, e)); +} + THttpInputHeader::THttpInputHeader(const TStringBuf header) { - size_t pos = header.find(':'); - + size_t pos = header.find(':'); + if (pos == TString::npos) { ythrow THttpParseException() << "can not parse http header(" << TString{header}.Quote() << ")"; - } - + } + Name_ = TString(header.cbegin(), header.cbegin() + pos); Value_ = ::ToString(Trim(header.cbegin() + pos + 1, header.cend())); -} - +} + THttpInputHeader::THttpInputHeader(TString name, TString value) : Name_(std::move(name)) , Value_(std::move(value)) -{ -} - +{ +} + void THttpInputHeader::OutTo(IOutputStream* stream) const { typedef IOutputStream::TPart TPart; - - const TPart parts[] = { - TPart(Name_), - TPart(": ", 2), - TPart(Value_), - TPart::CrLf(), - }; - - stream->Write(parts, sizeof(parts) / sizeof(*parts)); -} - + + const TPart parts[] = { + TPart(Name_), + TPart(": ", 2), + TPart(Value_), + TPart::CrLf(), + }; + + stream->Write(parts, sizeof(parts) / sizeof(*parts)); +} + THttpHeaders::THttpHeaders(IInputStream* stream) { TString header; TString line; - + bool rdOk = stream->ReadLine(header); while (rdOk && !header.empty()) { rdOk = stream->ReadLine(line); - + if (rdOk && ((line[0] == ' ') || (line[0] == '\t'))) { header += line; } else { AddHeader(THttpInputHeader(header)); header = line; - } - } -} - + } + } +} + bool THttpHeaders::HasHeader(const TStringBuf header) const { return FindHeader(header); } @@ -85,24 +85,24 @@ void THttpHeaders::AddOrReplaceHeader(const THttpInputHeader& header) { for (auto& hdr : Headers_) { if (AsciiCompareIgnoreCase(hdr.Name(), header.Name()) == 0) { hdr = header; - return; - } - } - - AddHeader(header); -} - + return; + } + } + + AddHeader(header); +} + void THttpHeaders::AddHeader(THttpInputHeader header) { Headers_.push_back(std::move(header)); -} - +} + void THttpHeaders::OutTo(IOutputStream* stream) const { - for (TConstIterator header = Begin(); header != End(); ++header) { - header->OutTo(stream); - } -} - -template <> + for (TConstIterator header = Begin(); header != End(); ++header) { + header->OutTo(stream); + } +} + +template <> void Out<THttpHeaders>(IOutputStream& out, const THttpHeaders& h) { - h.OutTo(&out); -} + h.OutTo(&out); +} diff --git a/library/cpp/http/io/headers.h b/library/cpp/http/io/headers.h index a6e130eaa0..a71793d1c6 100644 --- a/library/cpp/http/io/headers.h +++ b/library/cpp/http/io/headers.h @@ -1,99 +1,99 @@ #pragma once - + #include <util/generic/string.h> -#include <util/generic/strbuf.h> +#include <util/generic/strbuf.h> #include <util/generic/deque.h> #include <util/generic/vector.h> #include <util/string/cast.h> - + class IInputStream; class IOutputStream; - + /// @addtogroup Streams_HTTP /// @{ /// Объект, содержащий информацию о HTTP-заголовке. class THttpInputHeader { -public: - /// @param[in] header - строка вида 'параметр: значение'. +public: + /// @param[in] header - строка вида 'параметр: значение'. THttpInputHeader(TStringBuf header); - /// @param[in] name - имя параметра. - /// @param[in] value - значение параметра. + /// @param[in] name - имя параметра. + /// @param[in] value - значение параметра. THttpInputHeader(TString name, TString value); - - /// Возвращает имя параметра. + + /// Возвращает имя параметра. inline const TString& Name() const noexcept { - return Name_; - } - - /// Возвращает значение параметра. + return Name_; + } + + /// Возвращает значение параметра. inline const TString& Value() const noexcept { - return Value_; - } - - /// Записывает заголовок вида "имя параметра: значение\r\n" в поток. + return Value_; + } + + /// Записывает заголовок вида "имя параметра: значение\r\n" в поток. void OutTo(IOutputStream* stream) const; - - /// Возвращает строку "имя параметра: значение". + + /// Возвращает строку "имя параметра: значение". inline TString ToString() const { return Name_ + TStringBuf(": ") + Value_; - } - -private: + } + +private: TString Name_; TString Value_; -}; - +}; + /// Контейнер для хранения HTTP-заголовков -class THttpHeaders { +class THttpHeaders { using THeaders = TDeque<THttpInputHeader>; - -public: + +public: using TConstIterator = THeaders::const_iterator; - + THttpHeaders() = default; - /// Добавляет каждую строку из потока в контейнер, считая ее правильным заголовком. + /// Добавляет каждую строку из потока в контейнер, считая ее правильным заголовком. THttpHeaders(IInputStream* stream); - - /// Стандартный итератор. + + /// Стандартный итератор. inline TConstIterator Begin() const noexcept { - return Headers_.begin(); - } + return Headers_.begin(); + } inline TConstIterator begin() const noexcept { return Headers_.begin(); } - - /// Стандартный итератор. + + /// Стандартный итератор. inline TConstIterator End() const noexcept { - return Headers_.end(); - } + return Headers_.end(); + } inline TConstIterator end() const noexcept { return Headers_.end(); } - - /// Возвращает количество заголовков в контейнере. + + /// Возвращает количество заголовков в контейнере. inline size_t Count() const noexcept { - return Headers_.size(); - } - - /// Проверяет, содержит ли контейнер хотя бы один заголовок. + return Headers_.size(); + } + + /// Проверяет, содержит ли контейнер хотя бы один заголовок. inline bool Empty() const noexcept { - return Headers_.empty(); - } + return Headers_.empty(); + } - /// Добавляет заголовок в контейнер. + /// Добавляет заголовок в контейнер. void AddHeader(THttpInputHeader header); - + template <typename ValueType> void AddHeader(TString name, const ValueType& value) { AddHeader(THttpInputHeader(std::move(name), ToString(value))); } - /// Добавляет заголовок в контейнер, если тот не содержит заголовка - /// c таким же параметром. В противном случае, заменяет существующий - /// заголовок на новый. - void AddOrReplaceHeader(const THttpInputHeader& header); - + /// Добавляет заголовок в контейнер, если тот не содержит заголовка + /// c таким же параметром. В противном случае, заменяет существующий + /// заголовок на новый. + void AddOrReplaceHeader(const THttpInputHeader& header); + template <typename ValueType> void AddOrReplaceHeader(TString name, const ValueType& value) { AddOrReplaceHeader(THttpInputHeader(std::move(name), ToString(value))); @@ -109,17 +109,17 @@ public: /// Возвращает nullptr, если не нашел const THttpInputHeader* FindHeader(TStringBuf header) const; - /// Записывает все заголовки контейнера в поток. - /// @details Каждый заголовк записывается в виде "имя параметра: значение\r\n". + /// Записывает все заголовки контейнера в поток. + /// @details Каждый заголовк записывается в виде "имя параметра: значение\r\n". void OutTo(IOutputStream* stream) const; - /// Обменивает наборы заголовков двух контейнеров. + /// Обменивает наборы заголовков двух контейнеров. void Swap(THttpHeaders& headers) noexcept { - Headers_.swap(headers.Headers_); - } - -private: - THeaders Headers_; -}; - + Headers_.swap(headers.Headers_); + } + +private: + THeaders Headers_; +}; + /// @} diff --git a/library/cpp/http/io/headers_ut.cpp b/library/cpp/http/io/headers_ut.cpp index b68467f786..1d23ef8fdc 100644 --- a/library/cpp/http/io/headers_ut.cpp +++ b/library/cpp/http/io/headers_ut.cpp @@ -13,8 +13,8 @@ namespace { THeadersExistence(const THttpHeaders& headers) { for (THttpHeaders::TConstIterator it = headers.Begin(); - it != headers.End(); - ++it) { + it != headers.End(); + ++it) { Add(it->Name(), it->Value()); } } @@ -24,7 +24,7 @@ namespace { Impl.emplace(TString(name), TString(value)); } - bool operator==(const THeadersExistence& rhs) const { + bool operator==(const THeadersExistence& rhs) const { return Impl == rhs.Impl; } @@ -34,11 +34,11 @@ namespace { }; } -bool operator==(const THeadersExistence& lhs, const THttpHeaders& rhs) { +bool operator==(const THeadersExistence& lhs, const THttpHeaders& rhs) { return lhs == THeadersExistence(rhs); } -bool operator==(const THttpHeaders& lhs, const THeadersExistence& rhs) { +bool operator==(const THttpHeaders& lhs, const THeadersExistence& rhs) { return THeadersExistence(lhs) == rhs; } diff --git a/library/cpp/http/io/list_codings/main.cpp b/library/cpp/http/io/list_codings/main.cpp index f15b24f234..9818d02bdf 100644 --- a/library/cpp/http/io/list_codings/main.cpp +++ b/library/cpp/http/io/list_codings/main.cpp @@ -1,8 +1,8 @@ #include <library/cpp/http/io/stream.h> -#include <util/stream/output.h> - -int main() { - for (auto codec : SupportedCodings()) { - Cout << codec << Endl; - } -} +#include <util/stream/output.h> + +int main() { + for (auto codec : SupportedCodings()) { + Cout << codec << Endl; + } +} diff --git a/library/cpp/http/io/list_codings/ya.make b/library/cpp/http/io/list_codings/ya.make index 7559ba195c..e5c5fed6dc 100644 --- a/library/cpp/http/io/list_codings/ya.make +++ b/library/cpp/http/io/list_codings/ya.make @@ -1,13 +1,13 @@ -PROGRAM() - -OWNER(pg) - -PEERDIR( +PROGRAM() + +OWNER(pg) + +PEERDIR( library/cpp/http/io -) - -SRCS( - main.cpp -) - -END() +) + +SRCS( + main.cpp +) + +END() diff --git a/library/cpp/http/io/stream.cpp b/library/cpp/http/io/stream.cpp index c38faffe0b..6689be684f 100644 --- a/library/cpp/http/io/stream.cpp +++ b/library/cpp/http/io/stream.cpp @@ -1,156 +1,156 @@ -#include "stream.h" +#include "stream.h" #include "compression.h" -#include "chunk.h" - +#include "chunk.h" + #include <util/stream/buffered.h> -#include <util/stream/length.h> +#include <util/stream/length.h> #include <util/stream/multi.h> #include <util/stream/null.h> #include <util/stream/tee.h> - + #include <util/system/compat.h> -#include <util/system/yassert.h> - -#include <util/network/socket.h> - -#include <util/string/cast.h> +#include <util/system/yassert.h> + +#include <util/network/socket.h> + +#include <util/string/cast.h> #include <util/string/strip.h> - + #include <util/generic/string.h> -#include <util/generic/utility.h> -#include <util/generic/hash_set.h> -#include <util/generic/yexception.h> - -#define HEADERCMP(header, str) \ - case sizeof(str) - 1: \ +#include <util/generic/utility.h> +#include <util/generic/hash_set.h> +#include <util/generic/yexception.h> + +#define HEADERCMP(header, str) \ + case sizeof(str) - 1: \ if (!stricmp((header).Name().data(), str)) -namespace { +namespace { inline size_t SuggestBufferSize() { - return 8192; - } - + return 8192; + } + inline TStringBuf Trim(const char* b, const char* e) noexcept { - return StripString(TStringBuf(b, e)); - } - + return StripString(TStringBuf(b, e)); + } + inline TStringBuf RmSemiColon(const TStringBuf& s) { - return s.Before(';'); - } - - template <class T, size_t N> - class TStreams: private TNonCopyable { - struct TDelete { - inline void operator()(T* t) noexcept { - delete t; - } - }; - - typedef T* TPtr; - - public: - inline TStreams() noexcept - : Beg_(T_ + N) - { - } - - inline ~TStreams() { - TDelete f; - - ForEach(f); - } - - template <class S> - inline S* Add(S* t) noexcept { - return (S*)AddImpl((T*)t); - } - - template <class Functor> - inline void ForEach(Functor& f) { - const TPtr* end = T_ + N; - - for (TPtr* cur = Beg_; cur != end; ++cur) { - f(*cur); - } - } - - TPtr Top() { - const TPtr* end = T_ + N; - return end == Beg_ ? nullptr : *Beg_; - } - - private: - inline T* AddImpl(T* t) noexcept { - Y_ASSERT(Beg_ > T_); - - return (*--Beg_ = t); - } - - private: - TPtr T_[N]; - TPtr* Beg_; - }; - - template <class TStream> - class TLazy: public IOutputStream { - public: - TLazy(IOutputStream* out, ui16 bs) - : Output_(out) - , BlockSize_(bs) - { - } - - void DoWrite(const void* buf, size_t len) override { - ConstructSlave(); - Slave_->Write(buf, len); - } - - void DoFlush() override { - ConstructSlave(); - Slave_->Flush(); - } - - void DoFinish() override { - ConstructSlave(); - Slave_->Finish(); - } - - private: - inline void ConstructSlave() { - if (!Slave_) { - Slave_.Reset(new TStream(Output_, BlockSize_)); - } - } - - private: - IOutputStream* Output_; - ui16 BlockSize_; - THolder<IOutputStream> Slave_; - }; -} - -class THttpInput::TImpl { + return s.Before(';'); + } + + template <class T, size_t N> + class TStreams: private TNonCopyable { + struct TDelete { + inline void operator()(T* t) noexcept { + delete t; + } + }; + + typedef T* TPtr; + + public: + inline TStreams() noexcept + : Beg_(T_ + N) + { + } + + inline ~TStreams() { + TDelete f; + + ForEach(f); + } + + template <class S> + inline S* Add(S* t) noexcept { + return (S*)AddImpl((T*)t); + } + + template <class Functor> + inline void ForEach(Functor& f) { + const TPtr* end = T_ + N; + + for (TPtr* cur = Beg_; cur != end; ++cur) { + f(*cur); + } + } + + TPtr Top() { + const TPtr* end = T_ + N; + return end == Beg_ ? nullptr : *Beg_; + } + + private: + inline T* AddImpl(T* t) noexcept { + Y_ASSERT(Beg_ > T_); + + return (*--Beg_ = t); + } + + private: + TPtr T_[N]; + TPtr* Beg_; + }; + + template <class TStream> + class TLazy: public IOutputStream { + public: + TLazy(IOutputStream* out, ui16 bs) + : Output_(out) + , BlockSize_(bs) + { + } + + void DoWrite(const void* buf, size_t len) override { + ConstructSlave(); + Slave_->Write(buf, len); + } + + void DoFlush() override { + ConstructSlave(); + Slave_->Flush(); + } + + void DoFinish() override { + ConstructSlave(); + Slave_->Finish(); + } + + private: + inline void ConstructSlave() { + if (!Slave_) { + Slave_.Reset(new TStream(Output_, BlockSize_)); + } + } + + private: + IOutputStream* Output_; + ui16 BlockSize_; + THolder<IOutputStream> Slave_; + }; +} + +class THttpInput::TImpl { typedef THashSet<TString> TAcceptCodings; - -public: + +public: inline TImpl(IInputStream* slave) - : Slave_(slave) - , Buffered_(Slave_, SuggestBufferSize()) + : Slave_(slave) + , Buffered_(Slave_, SuggestBufferSize()) , ChunkedInput_(nullptr) , Input_(nullptr) , FirstLine_(ReadFirstLine(Buffered_)) - , Headers_(&Buffered_) - , KeepAlive_(false) - , HasContentLength_(false) - , ContentLength_(0) - , ContentEncoded_(false) + , Headers_(&Buffered_) + , KeepAlive_(false) + , HasContentLength_(false) + , ContentLength_(0) + , ContentEncoded_(false) , Expect100Continue_(false) - { - BuildInputChain(); + { + BuildInputChain(); Y_ASSERT(Input_); - } - + } + static TString ReadFirstLine(TBufferedInput& in) { TString s; Y_ENSURE_EX(in.ReadLine(s), THttpReadException() << "Failed to get first line"); @@ -158,48 +158,48 @@ public: } inline ~TImpl() { - } - - inline size_t Read(void* buf, size_t len) { + } + + inline size_t Read(void* buf, size_t len) { return Perform(len, [this, buf](size_t toRead) { return Input_->Read(buf, toRead); }); - } + } inline size_t Skip(size_t len) { return Perform(len, [this](size_t toSkip) { return Input_->Skip(toSkip); }); - } - + } + inline const TString& FirstLine() const noexcept { - return FirstLine_; - } - + return FirstLine_; + } + inline const THttpHeaders& Headers() const noexcept { - return Headers_; - } - + return Headers_; + } + inline const TMaybe<THttpHeaders>& Trailers() const noexcept { return Trailers_; } inline bool IsKeepAlive() const noexcept { - return KeepAlive_; - } - + return KeepAlive_; + } + inline bool AcceptEncoding(const TString& s) const { - return Codings_.find(to_lower(s)) != Codings_.end(); - } - + return Codings_.find(to_lower(s)) != Codings_.end(); + } + inline bool GetContentLength(ui64& value) const noexcept { - if (HasContentLength_) { - value = ContentLength_; - return true; + if (HasContentLength_) { + value = ContentLength_; + return true; } - return false; - } + return false; + } inline bool ContentEncoded() const noexcept { - return ContentEncoded_; - } - + return ContentEncoded_; + } + inline bool HasContent() const noexcept { return HasContentLength_ || ChunkedInput_; } @@ -208,8 +208,8 @@ public: return Expect100Continue_; } -private: - template <class Operation> +private: + template <class Operation> inline size_t Perform(size_t len, const Operation& operation) { size_t processed = operation(len); if (processed == 0 && len > 0) { @@ -227,52 +227,52 @@ private: return processed; } - struct TParsedHeaders { + struct TParsedHeaders { bool Chunked = false; bool KeepAlive = false; - TStringBuf LZipped; - }; - - struct TTrEnc { - inline void operator()(const TStringBuf& s) { + TStringBuf LZipped; + }; + + struct TTrEnc { + inline void operator()(const TStringBuf& s) { if (s == TStringBuf("chunked")) { p->Chunked = true; - } - } - - TParsedHeaders* p; - }; - - struct TAccCoding { - inline void operator()(const TStringBuf& s) { - c->insert(ToString(s)); - } - - TAcceptCodings* c; - }; - - template <class Functor> + } + } + + TParsedHeaders* p; + }; + + struct TAccCoding { + inline void operator()(const TStringBuf& s) { + c->insert(ToString(s)); + } + + TAcceptCodings* c; + }; + + template <class Functor> inline void ForEach(TString in, Functor& f) { - in.to_lower(); - - const char* b = in.begin(); - const char* c = b; - const char* e = in.end(); - - while (c != e) { - if (*c == ',') { - f(RmSemiColon(Trim(b, c))); - b = c + 1; - } - - ++c; - } - - if (b != c) { - f(RmSemiColon(Trim(b, c))); - } - } - + in.to_lower(); + + const char* b = in.begin(); + const char* c = b; + const char* e = in.end(); + + while (c != e) { + if (*c == ',') { + f(RmSemiColon(Trim(b, c))); + b = c + 1; + } + + ++c; + } + + if (b != c) { + f(RmSemiColon(Trim(b, c))); + } + } + inline bool IsRequest() const { return strnicmp(FirstLine().data(), "get", 3) == 0 || strnicmp(FirstLine().data(), "post", 4) == 0 || @@ -282,47 +282,47 @@ private: strnicmp(FirstLine().data(), "delete", 6) == 0; } - inline void BuildInputChain() { - TParsedHeaders p; + inline void BuildInputChain() { + TParsedHeaders p; - size_t pos = FirstLine_.rfind(' '); + size_t pos = FirstLine_.rfind(' '); // In HTTP/1.1 Keep-Alive is turned on by default if (pos != TString::npos && strcmp(FirstLine_.c_str() + pos + 1, "HTTP/1.1") == 0) { - p.KeepAlive = true; //request + p.KeepAlive = true; //request } else if (strnicmp(FirstLine_.data(), "HTTP/1.1", 8) == 0) { - p.KeepAlive = true; //reply - } - - for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) { - const THttpInputHeader& header = *h; + p.KeepAlive = true; //reply + } + + for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) { + const THttpInputHeader& header = *h; switch (header.Name().size()) { - HEADERCMP(header, "transfer-encoding") { - TTrEnc f = {&p}; - ForEach(header.Value(), f); - } - break; - HEADERCMP(header, "content-encoding") { - p.LZipped = header.Value(); - } - break; - HEADERCMP(header, "accept-encoding") { - TAccCoding f = {&Codings_}; - ForEach(header.Value(), f); - } - break; - HEADERCMP(header, "content-length") { - HasContentLength_ = true; - ContentLength_ = FromString(header.Value()); - } - break; - HEADERCMP(header, "connection") { - // accept header "Connection: Keep-Alive, TE" + HEADERCMP(header, "transfer-encoding") { + TTrEnc f = {&p}; + ForEach(header.Value(), f); + } + break; + HEADERCMP(header, "content-encoding") { + p.LZipped = header.Value(); + } + break; + HEADERCMP(header, "accept-encoding") { + TAccCoding f = {&Codings_}; + ForEach(header.Value(), f); + } + break; + HEADERCMP(header, "content-length") { + HasContentLength_ = true; + ContentLength_ = FromString(header.Value()); + } + break; + HEADERCMP(header, "connection") { + // accept header "Connection: Keep-Alive, TE" if (strnicmp(header.Value().data(), "keep-alive", 10) == 0) { p.KeepAlive = true; } else if (stricmp(header.Value().data(), "close") == 0) { p.KeepAlive = false; } - } + } [[fallthrough]]; HEADERCMP(header, "expect") { auto findContinue = [&](const TStringBuf& s) { @@ -332,101 +332,101 @@ private: }; ForEach(header.Value(), findContinue); } - break; - } - } - + break; + } + } + if (p.Chunked) { ChunkedInput_ = Streams_.Add(new TChunkedInput(&Buffered_, &Trailers_)); Input_ = ChunkedInput_; - } else { + } else { // disable buffering - Buffered_.Reset(&Cnull); - Input_ = Streams_.Add(new TMultiInput(&Buffered_, Slave_)); - + Buffered_.Reset(&Cnull); + Input_ = Streams_.Add(new TMultiInput(&Buffered_, Slave_)); + if (IsRequest() || HasContentLength_) { - /* - * TODO - we have other cases - */ - Input_ = Streams_.Add(new TLengthLimitedInput(Input_, ContentLength_)); - } - } - + /* + * TODO - we have other cases + */ + Input_ = Streams_.Add(new TLengthLimitedInput(Input_, ContentLength_)); + } + } + if (auto decoder = TCompressionCodecFactory::Instance().FindDecoder(p.LZipped)) { - ContentEncoded_ = true; + ContentEncoded_ = true; Input_ = Streams_.Add((*decoder)(Input_).Release()); - } - + } + KeepAlive_ = p.KeepAlive; - } - -private: + } + +private: IInputStream* Slave_; - - /* - * input helpers - */ - TBufferedInput Buffered_; + + /* + * input helpers + */ + TBufferedInput Buffered_; TStreams<IInputStream, 8> Streams_; IInputStream* ChunkedInput_; - - /* - * final input stream - */ + + /* + * final input stream + */ IInputStream* Input_; - + TString FirstLine_; - THttpHeaders Headers_; + THttpHeaders Headers_; TMaybe<THttpHeaders> Trailers_; - bool KeepAlive_; - - TAcceptCodings Codings_; + bool KeepAlive_; - bool HasContentLength_; - ui64 ContentLength_; + TAcceptCodings Codings_; - bool ContentEncoded_; + bool HasContentLength_; + ui64 ContentLength_; + + bool ContentEncoded_; bool Expect100Continue_; -}; - +}; + THttpInput::THttpInput(IInputStream* slave) - : Impl_(new TImpl(slave)) -{ -} - + : Impl_(new TImpl(slave)) +{ +} + THttpInput::THttpInput(THttpInput&& httpInput) = default; THttpInput::~THttpInput() { -} - -size_t THttpInput::DoRead(void* buf, size_t len) { - return Impl_->Read(buf, len); -} - +} + +size_t THttpInput::DoRead(void* buf, size_t len) { + return Impl_->Read(buf, len); +} + size_t THttpInput::DoSkip(size_t len) { return Impl_->Skip(len); } const THttpHeaders& THttpInput::Headers() const noexcept { - return Impl_->Headers(); -} - + return Impl_->Headers(); +} + const TMaybe<THttpHeaders>& THttpInput::Trailers() const noexcept { return Impl_->Trailers(); } const TString& THttpInput::FirstLine() const noexcept { - return Impl_->FirstLine(); -} - + return Impl_->FirstLine(); +} + bool THttpInput::IsKeepAlive() const noexcept { - return Impl_->IsKeepAlive(); -} - + return Impl_->IsKeepAlive(); +} + bool THttpInput::AcceptEncoding(const TString& coding) const { - return Impl_->AcceptEncoding(coding); -} - + return Impl_->AcceptEncoding(coding); +} + TString THttpInput::BestCompressionScheme(TArrayRef<const TStringBuf> codings) const { return NHttp::ChooseBestCompressionScheme( [this](const TString& coding) { @@ -434,8 +434,8 @@ TString THttpInput::BestCompressionScheme(TArrayRef<const TStringBuf> codings) c }, codings ); -} - +} + TString THttpInput::BestCompressionScheme() const { return BestCompressionScheme(TCompressionCodecFactory::Instance().GetBestCodecs()); } @@ -456,141 +456,141 @@ bool THttpInput::HasExpect100Continue() const noexcept { return Impl_->HasExpect100Continue(); } -class THttpOutput::TImpl { +class THttpOutput::TImpl { class TSizeCalculator: public IOutputStream { - public: + public: inline TSizeCalculator() noexcept { - } - + } + ~TSizeCalculator() override { - } - + } + void DoWrite(const void* /*buf*/, size_t len) override { - Length_ += len; - } - + Length_ += len; + } + inline size_t Length() const noexcept { - return Length_; - } - - private: + return Length_; + } + + private: size_t Length_ = 0; - }; - - enum TState { - Begin = 0, - FirstLineSent = 1, - HeadersSent = 2 - }; - - struct TFlush { + }; + + enum TState { + Begin = 0, + FirstLineSent = 1, + HeadersSent = 2 + }; + + struct TFlush { inline void operator()(IOutputStream* s) { - s->Flush(); - } - }; - - struct TFinish { + s->Flush(); + } + }; + + struct TFinish { inline void operator()(IOutputStream* s) { - s->Finish(); - } - }; - -public: + s->Finish(); + } + }; + +public: inline TImpl(IOutputStream* slave, THttpInput* request) - : Slave_(slave) - , State_(Begin) - , Output_(Slave_) - , Request_(request) - , Version_(1100) - , KeepAliveEnabled_(false) + : Slave_(slave) + , State_(Begin) + , Output_(Slave_) + , Request_(request) + , Version_(1100) + , KeepAliveEnabled_(false) , BodyEncodingEnabled_(true) , CompressionHeaderEnabled_(true) - , Finished_(false) - { - } - + , Finished_(false) + { + } + inline ~TImpl() { - } - + } + inline void SendContinue() { Output_->Write("HTTP/1.1 100 Continue\r\n\r\n"); Output_->Flush(); } - inline void Write(const void* buf, size_t len) { - if (Finished_) { - ythrow THttpException() << "can not write to finished stream"; - } - - if (State_ == HeadersSent) { - Output_->Write(buf, len); - - return; - } - - const char* b = (const char*)buf; - const char* e = b + len; - const char* c = b; - - while (c != e) { - if (*c == '\n') { - Line_.append(b, c); - + inline void Write(const void* buf, size_t len) { + if (Finished_) { + ythrow THttpException() << "can not write to finished stream"; + } + + if (State_ == HeadersSent) { + Output_->Write(buf, len); + + return; + } + + const char* b = (const char*)buf; + const char* e = b + len; + const char* c = b; + + while (c != e) { + if (*c == '\n') { + Line_.append(b, c); + if (!Line_.empty() && Line_.back() == '\r') { - Line_.pop_back(); - } - - b = c + 1; - - Process(Line_); - - if (State_ == HeadersSent) { - Output_->Write(b, e - b); - - return; - } - - Line_.clear(); - } - - ++c; - } - - if (b != c) { - Line_.append(b, c); - } - } - - inline void Flush() { - TFlush f; - Streams_.ForEach(f); + Line_.pop_back(); + } + + b = c + 1; + + Process(Line_); + + if (State_ == HeadersSent) { + Output_->Write(b, e - b); + + return; + } + + Line_.clear(); + } + + ++c; + } + + if (b != c) { + Line_.append(b, c); + } + } + + inline void Flush() { + TFlush f; + Streams_.ForEach(f); Slave_->Flush(); // see SEARCH-1030 - } - - inline void Finish() { - if (Finished_) { - return; - } - - TFinish f; - Streams_.ForEach(f); + } + + inline void Finish() { + if (Finished_) { + return; + } + + TFinish f; + Streams_.ForEach(f); Slave_->Finish(); // see SEARCH-1030 - - Finished_ = true; - } - + + Finished_ = true; + } + inline const THttpHeaders& SentHeaders() const noexcept { - return Headers_; - } - + return Headers_; + } + inline void EnableCompression(TArrayRef<const TStringBuf> schemas) { - ComprSchemas_ = schemas; - } - - inline void EnableKeepAlive(bool enable) { - KeepAliveEnabled_ = enable; - } - + ComprSchemas_ = schemas; + } + + inline void EnableKeepAlive(bool enable) { + KeepAliveEnabled_ = enable; + } + inline void EnableBodyEncoding(bool enable) { BodyEncodingEnabled_ = enable; } @@ -601,12 +601,12 @@ public: inline bool IsCompressionEnabled() const noexcept { return !ComprSchemas_.empty(); - } - + } + inline bool IsKeepAliveEnabled() const noexcept { - return KeepAliveEnabled_; - } - + return KeepAliveEnabled_; + } + inline bool IsBodyEncodingEnabled() const noexcept { return BodyEncodingEnabled_; } @@ -616,9 +616,9 @@ public: } inline bool CanBeKeepAlive() const noexcept { - return SupportChunkedTransfer() && IsKeepAliveEnabled() && (Request_ ? Request_->IsKeepAlive() : true); - } - + return SupportChunkedTransfer() && IsKeepAliveEnabled() && (Request_ ? Request_->IsKeepAlive() : true); + } + inline const TString& FirstLine() const noexcept { return FirstLine_; } @@ -627,18 +627,18 @@ public: return SizeCalculator_.Length(); } -private: +private: static inline bool IsResponse(const TString& s) noexcept { return strnicmp(s.data(), "HTTP/", 5) == 0; - } - + } + static inline bool IsRequest(const TString& s) noexcept { - return !IsResponse(s); - } - + return !IsResponse(s); + } + inline bool IsHttpRequest() const noexcept { - return IsRequest(FirstLine_); - } + return IsRequest(FirstLine_); + } inline bool HasResponseBody() const noexcept { if (IsHttpResponse()) { @@ -652,169 +652,169 @@ private: } inline bool IsHttpResponse() const noexcept { - return IsResponse(FirstLine_); - } - + return IsResponse(FirstLine_); + } + inline bool HasRequestBody() const noexcept { return strnicmp(FirstLine_.data(), "POST", 4) == 0 || strnicmp(FirstLine_.data(), "PATCH", 5) == 0 || strnicmp(FirstLine_.data(), "PUT", 3) == 0; - } + } static inline size_t ParseHttpVersion(const TString& s) { - if (s.empty()) { - ythrow THttpParseException() << "malformed http stream"; + if (s.empty()) { + ythrow THttpParseException() << "malformed http stream"; } - - size_t parsed_version = 0; - - if (IsResponse(s)) { + + size_t parsed_version = 0; + + if (IsResponse(s)) { const char* b = s.data() + 5; - - while (*b && *b != ' ') { - if (*b != '.') { - parsed_version *= 10; - parsed_version += (*b - '0'); - } - - ++b; - } - } else { - /* - * s not empty here - */ - const char* e = s.end() - 1; - const char* b = s.begin(); - size_t mult = 1; - - while (e != b && *e != '/') { - if (*e != '.') { - parsed_version += (*e - '0') * mult; - mult *= 10; - } - - --e; - } - } - - return parsed_version * 100; - } - - inline void ParseHttpVersion() { - size_t parsed_version = ParseHttpVersion(FirstLine_); - - if (Request_) { - parsed_version = Min(parsed_version, ParseHttpVersion(Request_->FirstLine())); - } - - Version_ = parsed_version; - } - + + while (*b && *b != ' ') { + if (*b != '.') { + parsed_version *= 10; + parsed_version += (*b - '0'); + } + + ++b; + } + } else { + /* + * s not empty here + */ + const char* e = s.end() - 1; + const char* b = s.begin(); + size_t mult = 1; + + while (e != b && *e != '/') { + if (*e != '.') { + parsed_version += (*e - '0') * mult; + mult *= 10; + } + + --e; + } + } + + return parsed_version * 100; + } + + inline void ParseHttpVersion() { + size_t parsed_version = ParseHttpVersion(FirstLine_); + + if (Request_) { + parsed_version = Min(parsed_version, ParseHttpVersion(Request_->FirstLine())); + } + + Version_ = parsed_version; + } + inline void Process(const TString& s) { Y_ASSERT(State_ != HeadersSent); - - if (State_ == Begin) { - FirstLine_ = s; - ParseHttpVersion(); - State_ = FirstLineSent; - } else { - if (s.empty()) { - BuildOutputStream(); - WriteCached(); - State_ = HeadersSent; - } else { + + if (State_ == Begin) { + FirstLine_ = s; + ParseHttpVersion(); + State_ = FirstLineSent; + } else { + if (s.empty()) { + BuildOutputStream(); + WriteCached(); + State_ = HeadersSent; + } else { AddHeader(THttpInputHeader(s)); - } - } - } - + } + } + } + inline void WriteCachedImpl(IOutputStream* s) const { s->Write(FirstLine_.data(), FirstLine_.size()); - s->Write("\r\n", 2); - Headers_.OutTo(s); - s->Write("\r\n", 2); - s->Finish(); - } - - inline void WriteCached() { - size_t buflen = 0; - - { - TSizeCalculator out; - - WriteCachedImpl(&out); - buflen = out.Length(); - } - - { - TBufferedOutput out(Slave_, buflen); - - WriteCachedImpl(&out); - } - - if (IsHttpRequest() && !HasRequestBody()) { - /* - * if this is http request, then send it now - */ - - Slave_->Flush(); - } - } - + s->Write("\r\n", 2); + Headers_.OutTo(s); + s->Write("\r\n", 2); + s->Finish(); + } + + inline void WriteCached() { + size_t buflen = 0; + + { + TSizeCalculator out; + + WriteCachedImpl(&out); + buflen = out.Length(); + } + + { + TBufferedOutput out(Slave_, buflen); + + WriteCachedImpl(&out); + } + + if (IsHttpRequest() && !HasRequestBody()) { + /* + * if this is http request, then send it now + */ + + Slave_->Flush(); + } + } + inline bool SupportChunkedTransfer() const noexcept { - return Version_ >= 1100; - } - - inline void BuildOutputStream() { - if (CanBeKeepAlive()) { - AddOrReplaceHeader(THttpInputHeader("Connection", "Keep-Alive")); - } else { - AddOrReplaceHeader(THttpInputHeader("Connection", "Close")); - } - - if (IsHttpResponse()) { + return Version_ >= 1100; + } + + inline void BuildOutputStream() { + if (CanBeKeepAlive()) { + AddOrReplaceHeader(THttpInputHeader("Connection", "Keep-Alive")); + } else { + AddOrReplaceHeader(THttpInputHeader("Connection", "Close")); + } + + if (IsHttpResponse()) { if (Request_ && IsCompressionEnabled() && HasResponseBody()) { TString scheme = Request_->BestCompressionScheme(ComprSchemas_); - if (scheme != "identity") { - AddOrReplaceHeader(THttpInputHeader("Content-Encoding", scheme)); + if (scheme != "identity") { + AddOrReplaceHeader(THttpInputHeader("Content-Encoding", scheme)); RemoveHeader("Content-Length"); - } - } - - RebuildStream(); - } else { - if (IsCompressionEnabled()) { - AddOrReplaceHeader(THttpInputHeader("Accept-Encoding", BuildAcceptEncoding())); - } - if (HasRequestBody()) { - RebuildStream(); - } - } - } - + } + } + + RebuildStream(); + } else { + if (IsCompressionEnabled()) { + AddOrReplaceHeader(THttpInputHeader("Accept-Encoding", BuildAcceptEncoding())); + } + if (HasRequestBody()) { + RebuildStream(); + } + } + } + inline TString BuildAcceptEncoding() const { TString ret; - + for (const auto& coding : ComprSchemas_) { - if (ret) { - ret += ", "; - } - + if (ret) { + ret += ", "; + } + ret += coding; - } - - return ret; - } + } + + return ret; + } - inline void RebuildStream() { + inline void RebuildStream() { bool keepAlive = false; const TCompressionCodecFactory::TEncoderConstructor* encoder = nullptr; - bool chunked = false; + bool chunked = false; bool haveContentLength = false; - - for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) { - const THttpInputHeader& header = *h; + + for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) { + const THttpInputHeader& header = *h; const TString hl = to_lower(header.Name()); - + if (hl == TStringBuf("connection")) { keepAlive = to_lower(header.Value()) == TStringBuf("keep-alive"); } else if (IsCompressionHeaderEnabled() && hl == TStringBuf("content-encoding")) { @@ -823,109 +823,109 @@ private: chunked = to_lower(header.Value()) == TStringBuf("chunked"); } else if (hl == TStringBuf("content-length")) { haveContentLength = true; - } - } - + } + } + if (!haveContentLength && !chunked && (IsHttpRequest() || HasResponseBody()) && SupportChunkedTransfer() && (keepAlive || encoder || IsHttpRequest())) { - AddHeader(THttpInputHeader("Transfer-Encoding", "chunked")); - chunked = true; - } - + AddHeader(THttpInputHeader("Transfer-Encoding", "chunked")); + chunked = true; + } + if (IsBodyEncodingEnabled() && chunked) { - Output_ = Streams_.Add(new TChunkedOutput(Output_)); - } - + Output_ = Streams_.Add(new TChunkedOutput(Output_)); + } + Output_ = Streams_.Add(new TTeeOutput(Output_, &SizeCalculator_)); if (IsBodyEncodingEnabled() && encoder) { Output_ = Streams_.Add((*encoder)(Output_).Release()); - } - } - - inline void AddHeader(const THttpInputHeader& hdr) { - Headers_.AddHeader(hdr); - } - - inline void AddOrReplaceHeader(const THttpInputHeader& hdr) { - Headers_.AddOrReplaceHeader(hdr); - } - + } + } + + inline void AddHeader(const THttpInputHeader& hdr) { + Headers_.AddHeader(hdr); + } + + inline void AddOrReplaceHeader(const THttpInputHeader& hdr) { + Headers_.AddOrReplaceHeader(hdr); + } + inline void RemoveHeader(const TString& hdr) { Headers_.RemoveHeader(hdr); } -private: +private: IOutputStream* Slave_; - TState State_; + TState State_; IOutputStream* Output_; TStreams<IOutputStream, 8> Streams_; TString Line_; TString FirstLine_; - THttpHeaders Headers_; - THttpInput* Request_; - size_t Version_; - + THttpHeaders Headers_; + THttpInput* Request_; + size_t Version_; + TArrayRef<const TStringBuf> ComprSchemas_; - - bool KeepAliveEnabled_; + + bool KeepAliveEnabled_; bool BodyEncodingEnabled_; bool CompressionHeaderEnabled_; - bool Finished_; + bool Finished_; TSizeCalculator SizeCalculator_; -}; - +}; + THttpOutput::THttpOutput(IOutputStream* slave) : Impl_(new TImpl(slave, nullptr)) -{ -} - +{ +} + THttpOutput::THttpOutput(IOutputStream* slave, THttpInput* request) - : Impl_(new TImpl(slave, request)) -{ -} - + : Impl_(new TImpl(slave, request)) +{ +} + THttpOutput::~THttpOutput() { - try { - Finish(); - } catch (...) { - } -} - -void THttpOutput::DoWrite(const void* buf, size_t len) { - Impl_->Write(buf, len); -} - -void THttpOutput::DoFlush() { - Impl_->Flush(); -} - -void THttpOutput::DoFinish() { - Impl_->Finish(); -} - + try { + Finish(); + } catch (...) { + } +} + +void THttpOutput::DoWrite(const void* buf, size_t len) { + Impl_->Write(buf, len); +} + +void THttpOutput::DoFlush() { + Impl_->Flush(); +} + +void THttpOutput::DoFinish() { + Impl_->Finish(); +} + const THttpHeaders& THttpOutput::SentHeaders() const noexcept { return Impl_->SentHeaders(); -} - -void THttpOutput::EnableCompression(bool enable) { - if (enable) { +} + +void THttpOutput::EnableCompression(bool enable) { + if (enable) { EnableCompression(TCompressionCodecFactory::Instance().GetBestCodecs()); - } else { + } else { TArrayRef<TStringBuf> codings; EnableCompression(codings); - } -} - + } +} + void THttpOutput::EnableCompression(TArrayRef<const TStringBuf> schemas) { Impl_->EnableCompression(schemas); -} - -void THttpOutput::EnableKeepAlive(bool enable) { - Impl_->EnableKeepAlive(enable); -} - +} + +void THttpOutput::EnableKeepAlive(bool enable) { + Impl_->EnableKeepAlive(enable); +} + void THttpOutput::EnableBodyEncoding(bool enable) { Impl_->EnableBodyEncoding(enable); } @@ -935,25 +935,25 @@ void THttpOutput::EnableCompressionHeader(bool enable) { } bool THttpOutput::IsKeepAliveEnabled() const noexcept { - return Impl_->IsKeepAliveEnabled(); -} - + return Impl_->IsKeepAliveEnabled(); +} + bool THttpOutput::IsBodyEncodingEnabled() const noexcept { return Impl_->IsBodyEncodingEnabled(); } bool THttpOutput::IsCompressionEnabled() const noexcept { - return Impl_->IsCompressionEnabled(); -} - + return Impl_->IsCompressionEnabled(); +} + bool THttpOutput::IsCompressionHeaderEnabled() const noexcept { return Impl_->IsCompressionHeaderEnabled(); } bool THttpOutput::CanBeKeepAlive() const noexcept { - return Impl_->CanBeKeepAlive(); -} - + return Impl_->CanBeKeepAlive(); +} + void THttpOutput::SendContinue() { Impl_->SendContinue(); } @@ -966,13 +966,13 @@ size_t THttpOutput::SentSize() const noexcept { return Impl_->SentSize(); } -unsigned ParseHttpRetCode(const TStringBuf& ret) { - const TStringBuf code = StripString(StripString(ret.After(' ')).Before(' ')); - +unsigned ParseHttpRetCode(const TStringBuf& ret) { + const TStringBuf code = StripString(StripString(ret.After(' ')).Before(' ')); + return FromString<unsigned>(code.data(), code.size()); -} +} -void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent, const TStringBuf& from) { +void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent, const TStringBuf& from) { TSocketOutput so(s); THttpOutput output(&so); @@ -995,11 +995,11 @@ void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf IOutputStream::TPart::CrLf(), IOutputStream::TPart::CrLf(), }; - + output.Write(parts, sizeof(parts) / sizeof(*parts)); output.Finish(); } - + TArrayRef<const TStringBuf> SupportedCodings() { return TCompressionCodecFactory::Instance().GetBestCodecs(); -} +} diff --git a/library/cpp/http/io/stream.h b/library/cpp/http/io/stream.h index ab69a8abab..78ca4fc814 100644 --- a/library/cpp/http/io/stream.h +++ b/library/cpp/http/io/stream.h @@ -1,40 +1,40 @@ #pragma once - -#include "headers.h" - + +#include "headers.h" + #include <util/stream/output.h> #include <util/generic/maybe.h> #include <util/generic/ptr.h> #include <util/generic/string.h> -#include <util/generic/strbuf.h> +#include <util/generic/strbuf.h> #include <util/generic/yexception.h> -#include <util/generic/array_ref.h> - -class TSocket; - -struct THttpException: public yexception { -}; - -struct THttpParseException: public THttpException { -}; - +#include <util/generic/array_ref.h> + +class TSocket; + +struct THttpException: public yexception { +}; + +struct THttpParseException: public THttpException { +}; + struct THttpReadException: public THttpException { }; /// Чтение ответа HTTP-сервера. class THttpInput: public IInputStream { -public: +public: THttpInput(IInputStream* slave); THttpInput(THttpInput&& httpInput); ~THttpInput() override; - - /* - * parsed http headers - */ - /// Возвращает контейнер с заголовками ответа HTTP-сервера. + + /* + * parsed http headers + */ + /// Возвращает контейнер с заголовками ответа HTTP-сервера. const THttpHeaders& Headers() const noexcept; - - /* + + /* * parsed http trailers */ /// Возвращает контейнер (возможно пустой) с trailer'ами ответа HTTP-сервера. @@ -44,78 +44,78 @@ public: const TMaybe<THttpHeaders>& Trailers() const noexcept; /* - * first line - response or request - */ - /// Возвращает первую строку ответа HTTP-сервера. - /// @details Первая строка HTTP-сервера - строка состояния, - /// содержащая три поля: версию HTTP, код состояния и описание. + * first line - response or request + */ + /// Возвращает первую строку ответа HTTP-сервера. + /// @details Первая строка HTTP-сервера - строка состояния, + /// содержащая три поля: версию HTTP, код состояния и описание. const TString& FirstLine() const noexcept; - - /* - * connection can be keep-alive - */ - /// Проверяет, не завершено ли соединение с сервером. - /// @details Транзакция считается завершенной, если не передан заголовок - /// "Connection: Keep Alive". + + /* + * connection can be keep-alive + */ + /// Проверяет, не завершено ли соединение с сервером. + /// @details Транзакция считается завершенной, если не передан заголовок + /// "Connection: Keep Alive". bool IsKeepAlive() const noexcept; - - /* - * output data can be encoded - */ - /// Проверяет, поддерживается ли данный тип кодирования содержимого - /// ответа HTTP-сервера. + + /* + * output data can be encoded + */ + /// Проверяет, поддерживается ли данный тип кодирования содержимого + /// ответа HTTP-сервера. bool AcceptEncoding(const TString& coding) const; - /// Пытается определить наилучший тип кодирования ответа HTTP-сервера. - /// @details Если ответ сервера говорит о том, что поддерживаются - /// любые типы кодирования, выбирается gzip. В противном случае - /// из списка типов кодирования выбирается лучший из поддерживаемых сервером. + /// Пытается определить наилучший тип кодирования ответа HTTP-сервера. + /// @details Если ответ сервера говорит о том, что поддерживаются + /// любые типы кодирования, выбирается gzip. В противном случае + /// из списка типов кодирования выбирается лучший из поддерживаемых сервером. TString BestCompressionScheme() const; TString BestCompressionScheme(TArrayRef<const TStringBuf> codings) const; - - /// Если заголовки содержат Content-Length, возвращает true и - /// записывает значение из заголовка в value + + /// Если заголовки содержат Content-Length, возвращает true и + /// записывает значение из заголовка в value bool GetContentLength(ui64& value) const noexcept; - /// Признак запакованности данных, - если выставлен, то Content-Length, при наличии в заголовках, - /// показывает объём запакованных данных, а из THttpInput мы будем вычитывать уже распакованные. + /// Признак запакованности данных, - если выставлен, то Content-Length, при наличии в заголовках, + /// показывает объём запакованных данных, а из THttpInput мы будем вычитывать уже распакованные. bool ContentEncoded() const noexcept; - + /// Returns true if Content-Length or Transfer-Encoding header received bool HasContent() const noexcept; bool HasExpect100Continue() const noexcept; -private: +private: size_t DoRead(void* buf, size_t len) override; size_t DoSkip(size_t len) override; - -private: - class TImpl; - THolder<TImpl> Impl_; -}; - + +private: + class TImpl; + THolder<TImpl> Impl_; +}; + /// Передача запроса HTTP-серверу. class THttpOutput: public IOutputStream { -public: +public: THttpOutput(IOutputStream* slave); THttpOutput(IOutputStream* slave, THttpInput* request); ~THttpOutput() override; - - /* - * sent http headers - */ - /// Возвращает контейнер с заголовками запроса к HTTP-серверу. + + /* + * sent http headers + */ + /// Возвращает контейнер с заголовками запроса к HTTP-серверу. const THttpHeaders& SentHeaders() const noexcept; - - /// Устанавливает режим, при котором сервер выдает ответ в упакованном виде. - void EnableCompression(bool enable); + + /// Устанавливает режим, при котором сервер выдает ответ в упакованном виде. + void EnableCompression(bool enable); void EnableCompression(TArrayRef<const TStringBuf> schemas); - /// Устанавливает режим, при котором соединение с сервером не завершается - /// после окончания транзакции. - void EnableKeepAlive(bool enable); - + /// Устанавливает режим, при котором соединение с сервером не завершается + /// после окончания транзакции. + void EnableKeepAlive(bool enable); + /// Устанавливает режим, при котором тело HTTP-запроса/ответа преобразуется в соответствии /// с заголовками Content-Encoding и Transfer-Encoding (включен по умолчанию) void EnableBodyEncoding(bool enable); @@ -124,12 +124,12 @@ public: /// указанным в Content-Encoding (включен по умолчанию) void EnableCompressionHeader(bool enable); - /// Проверяет, производится ли выдача ответов в упакованном виде. + /// Проверяет, производится ли выдача ответов в упакованном виде. bool IsCompressionEnabled() const noexcept; - /// Проверяет, не завершается ли соединение с сервером после окончания транзакции. + /// Проверяет, не завершается ли соединение с сервером после окончания транзакции. bool IsKeepAliveEnabled() const noexcept; - + /// Проверяет, преобразуется ли тело HTTP-запроса/ответа в соответствии /// с заголовками Content-Encoding и Transfer-Encoding bool IsBodyEncodingEnabled() const noexcept; @@ -138,13 +138,13 @@ public: /// указанным в Content-Encoding bool IsCompressionHeaderEnabled() const noexcept; - /* - * is this connection can be really keep-alive - */ - /// Проверяет, можно ли установить режим, при котором соединение с сервером - /// не завершается после окончания транзакции. + /* + * is this connection can be really keep-alive + */ + /// Проверяет, можно ли установить режим, при котором соединение с сервером + /// не завершается после окончания транзакции. bool CanBeKeepAlive() const noexcept; - + void SendContinue(); /* @@ -157,22 +157,22 @@ public: /// учёта chunked transfer encoding) size_t SentSize() const noexcept; -private: +private: void DoWrite(const void* buf, size_t len) override; void DoFlush() override; void DoFinish() override; - -private: - class TImpl; - THolder<TImpl> Impl_; -}; - + +private: + class TImpl; + THolder<TImpl> Impl_; +}; + /// Возвращает код состояния из ответа сервера. -unsigned ParseHttpRetCode(const TStringBuf& ret); - +unsigned ParseHttpRetCode(const TStringBuf& ret); + /// Отправляет HTTP-серверу запрос с минимумом необходимых заголовков. -void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent = "YandexSomething/1.0", const TStringBuf& from = "webadmin@yandex.ru"); +void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent = "YandexSomething/1.0", const TStringBuf& from = "webadmin@yandex.ru"); TArrayRef<const TStringBuf> SupportedCodings(); - + /// @} diff --git a/library/cpp/http/io/stream_ut.cpp b/library/cpp/http/io/stream_ut.cpp index b597320405..1ea35df675 100644 --- a/library/cpp/http/io/stream_ut.cpp +++ b/library/cpp/http/io/stream_ut.cpp @@ -1,19 +1,19 @@ -#include "stream.h" +#include "stream.h" #include "chunk.h" - + #include <library/cpp/http/server/http_ex.h> - + #include <library/cpp/testing/unittest/registar.h> #include <library/cpp/testing/unittest/tests_data.h> - -#include <util/string/printf.h> -#include <util/network/socket.h> + +#include <util/string/printf.h> +#include <util/network/socket.h> #include <util/stream/file.h> #include <util/stream/output.h> #include <util/stream/tee.h> -#include <util/stream/zlib.h> +#include <util/stream/zlib.h> #include <util/stream/null.h> - + Y_UNIT_TEST_SUITE(THttpStreamTest) { class TTestHttpServer: public THttpServer::ICallBack { class TRequest: public THttpClientRequestEx { @@ -34,12 +34,12 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { // "lo" is for "local" if (RD.ServerName() == "yandex.lo") { // do redirect - Output() << "HTTP/1.1 301 Moved permanently\r\n" - "Location: http://www.yandex.lo\r\n" - "\r\n"; + Output() << "HTTP/1.1 301 Moved permanently\r\n" + "Location: http://www.yandex.lo\r\n" + "\r\n"; } else if (RD.ServerName() == "www.yandex.lo") { - Output() << "HTTP/1.1 200 Ok\r\n" - "\r\n"; + Output() << "HTTP/1.1 200 Ok\r\n" + "\r\n"; } else { Output() << "HTTP/1.1 200 Ok\r\n\r\n"; if (Buf.Size()) { @@ -80,7 +80,7 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { Y_UNIT_TEST(TestCodings1) { UNIT_ASSERT(SupportedCodings().size() > 0); - } + } Y_UNIT_TEST(TestHttpInput) { TString res = "I'm a teapot"; @@ -93,41 +93,41 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { UNIT_ASSERT(server.Start()); TNetworkAddress addr("localhost", port); - TSocket s(addr); - - //TDebugOutput dbg; - TNullOutput dbg; - - { - TSocketOutput so(s); - TTeeOutput out(&so, &dbg); - THttpOutput output(&out); - - output.EnableKeepAlive(true); - output.EnableCompression(true); - + TSocket s(addr); + + //TDebugOutput dbg; + TNullOutput dbg; + + { + TSocketOutput so(s); + TTeeOutput out(&so, &dbg); + THttpOutput output(&out); + + output.EnableKeepAlive(true); + output.EnableCompression(true); + TString r; - r += "GET / HTTP/1.1"; - r += "\r\n"; + r += "GET / HTTP/1.1"; + r += "\r\n"; r += "Host: yandex.lo"; - r += "\r\n"; - r += "\r\n"; - + r += "\r\n"; + r += "\r\n"; + output.Write(r.data(), r.size()); - output.Finish(); - } - - { - TSocketInput si(s); - THttpInput input(&si); - unsigned httpCode = ParseHttpRetCode(input.FirstLine()); - UNIT_ASSERT_VALUES_EQUAL(httpCode / 10, 30u); - - TransferData(&input, &dbg); - } + output.Finish(); + } + + { + TSocketInput si(s); + THttpInput input(&si); + unsigned httpCode = ParseHttpRetCode(input.FirstLine()); + UNIT_ASSERT_VALUES_EQUAL(httpCode / 10, 30u); + + TransferData(&input, &dbg); + } server.Stop(); } - + Y_UNIT_TEST(TestHttpInputDelete) { TString res = "I'm a teapot"; TPortManager pm; @@ -175,9 +175,9 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { } Y_UNIT_TEST(TestParseHttpRetCode) { - UNIT_ASSERT_VALUES_EQUAL(ParseHttpRetCode("HTTP/1.1 301"), 301u); - } - + UNIT_ASSERT_VALUES_EQUAL(ParseHttpRetCode("HTTP/1.1 301"), 301u); + } + Y_UNIT_TEST(TestKeepAlive) { { TString s = "GET / HTTP/1.0\r\n\r\n"; @@ -248,19 +248,19 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { TNetworkAddress addr("localhost", port); - TSocket s(addr); - TNullOutput dbg; - + TSocket s(addr); + TNullOutput dbg; + SendMinimalHttpRequest(s, "www.yandex.lo", "/"); - + TSocketInput si(s); - THttpInput input(&si); + THttpInput input(&si); unsigned httpCode = ParseHttpRetCode(input.FirstLine()); - UNIT_ASSERT_VALUES_EQUAL(httpCode, 200u); - - TransferData(&input, &dbg); + UNIT_ASSERT_VALUES_EQUAL(httpCode, 200u); + + TransferData(&input, &dbg); server.Stop(); - } + } Y_UNIT_TEST(TestResponseWithBlanks) { TString res = "qqqqqq\r\n\r\nsdasdsad\r\n"; @@ -276,7 +276,7 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { TSocket s(addr); - SendMinimalHttpRequest(s, "www.yandex.ru", "/"); + SendMinimalHttpRequest(s, "www.yandex.ru", "/"); TSocketInput si(s); THttpInput input(&si); @@ -289,70 +289,70 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { Y_UNIT_TEST(TestOutputFlush) { TString str; - TStringOutput strOut(str); - TBufferedOutput bufOut(&strOut, 8192); - THttpOutput httpOut(&bufOut); + TStringOutput strOut(str); + TBufferedOutput bufOut(&strOut, 8192); + THttpOutput httpOut(&bufOut); + + httpOut.EnableKeepAlive(true); + httpOut.EnableCompression(true); - httpOut.EnableKeepAlive(true); - httpOut.EnableCompression(true); - - const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; - httpOut << header; + const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; + httpOut << header; unsigned curLen = str.size(); - const char* body = "<html>Hello</html>"; - httpOut << body; + const char* body = "<html>Hello</html>"; + httpOut << body; UNIT_ASSERT_VALUES_EQUAL(curLen, str.size()); - httpOut.Flush(); + httpOut.Flush(); UNIT_ASSERT_VALUES_EQUAL(curLen + strlen(body), str.size()); - } + } Y_UNIT_TEST(TestOutputPostFlush) { TString str; TString checkStr; - TStringOutput strOut(str); - TStringOutput checkOut(checkStr); - TBufferedOutput bufOut(&strOut, 8192); - TTeeOutput teeOut(&bufOut, &checkOut); - THttpOutput httpOut(&teeOut); + TStringOutput strOut(str); + TStringOutput checkOut(checkStr); + TBufferedOutput bufOut(&strOut, 8192); + TTeeOutput teeOut(&bufOut, &checkOut); + THttpOutput httpOut(&teeOut); - httpOut.EnableKeepAlive(true); - httpOut.EnableCompression(true); + httpOut.EnableKeepAlive(true); + httpOut.EnableCompression(true); - const char* header = "POST / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; - httpOut << header; + const char* header = "POST / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; + httpOut << header; UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u); - const char* body = "<html>Hello</html>"; - httpOut << body; + const char* body = "<html>Hello</html>"; + httpOut << body; UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u); - httpOut.Flush(); + httpOut.Flush(); UNIT_ASSERT_VALUES_EQUAL(checkStr.size(), str.size()); - } + } TString MakeHttpOutputBody(const char* body, bool encodingEnabled) { TString str; - TStringOutput strOut(str); - { - TBufferedOutput bufOut(&strOut, 8192); - THttpOutput httpOut(&bufOut); + TStringOutput strOut(str); + { + TBufferedOutput bufOut(&strOut, 8192); + THttpOutput httpOut(&bufOut); - httpOut.EnableKeepAlive(true); - httpOut.EnableCompression(true); + httpOut.EnableKeepAlive(true); + httpOut.EnableCompression(true); httpOut.EnableBodyEncoding(encodingEnabled); - httpOut << "POST / HTTP/1.1\r\n"; - httpOut << "Host: yandex.ru\r\n"; - httpOut << "Content-Encoding: gzip\r\n"; - httpOut << "\r\n"; + httpOut << "POST / HTTP/1.1\r\n"; + httpOut << "Host: yandex.ru\r\n"; + httpOut << "Content-Encoding: gzip\r\n"; + httpOut << "\r\n"; UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u); - httpOut << body; - } - const char* bodyDelimiter = "\r\n\r\n"; - size_t bodyPos = str.find(bodyDelimiter); + httpOut << body; + } + const char* bodyDelimiter = "\r\n\r\n"; + size_t bodyPos = str.find(bodyDelimiter); UNIT_ASSERT(bodyPos != TString::npos); return str.substr(bodyPos + strlen(bodyDelimiter)); }; @@ -370,54 +370,54 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { const char* body = "<html>Hello</html>"; UNIT_ASSERT(MakeHttpOutputBody(body, false) == body); UNIT_ASSERT(MakeHttpOutputBody(body, true) == SimulateBodyEncoding(body)); - } - + } + Y_UNIT_TEST(TestOutputFinish) { TString str; - TStringOutput strOut(str); - TBufferedOutput bufOut(&strOut, 8192); + TStringOutput strOut(str); + TBufferedOutput bufOut(&strOut, 8192); THttpOutput httpOut(&bufOut); httpOut.EnableKeepAlive(true); httpOut.EnableCompression(true); - const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; - httpOut << header; + const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n"; + httpOut << header; unsigned curLen = str.size(); - const char* body = "<html>Hello</html>"; + const char* body = "<html>Hello</html>"; httpOut << body; UNIT_ASSERT_VALUES_EQUAL(curLen, str.size()); - httpOut.Finish(); + httpOut.Finish(); UNIT_ASSERT_VALUES_EQUAL(curLen + strlen(body), str.size()); } Y_UNIT_TEST(TestMultilineHeaders) { - const char* headerLine0 = "HTTP/1.1 200 OK"; - const char* headerLine1 = "Content-Language: en"; - const char* headerLine2 = "Vary: Accept-Encoding, "; - const char* headerLine3 = "\tAccept-Language"; - const char* headerLine4 = "Content-Length: 18"; + const char* headerLine0 = "HTTP/1.1 200 OK"; + const char* headerLine1 = "Content-Language: en"; + const char* headerLine2 = "Vary: Accept-Encoding, "; + const char* headerLine3 = "\tAccept-Language"; + const char* headerLine4 = "Content-Length: 18"; TString endLine("\r\n"); TString r; - r += headerLine0 + endLine; - r += headerLine1 + endLine; - r += headerLine2 + endLine; - r += headerLine3 + endLine; - r += headerLine4 + endLine + endLine; - r += "<html>Hello</html>"; - TStringInput stringInput(r); - THttpInput input(&stringInput); - - const THttpHeaders& httpHeaders = input.Headers(); - UNIT_ASSERT_VALUES_EQUAL(httpHeaders.Count(), 3u); - - THttpHeaders::TConstIterator it = httpHeaders.Begin(); + r += headerLine0 + endLine; + r += headerLine1 + endLine; + r += headerLine2 + endLine; + r += headerLine3 + endLine; + r += headerLine4 + endLine + endLine; + r += "<html>Hello</html>"; + TStringInput stringInput(r); + THttpInput input(&stringInput); + + const THttpHeaders& httpHeaders = input.Headers(); + UNIT_ASSERT_VALUES_EQUAL(httpHeaders.Count(), 3u); + + THttpHeaders::TConstIterator it = httpHeaders.Begin(); UNIT_ASSERT_VALUES_EQUAL(it->ToString(), TString(headerLine1)); UNIT_ASSERT_VALUES_EQUAL((++it)->ToString(), TString::Join(headerLine2, headerLine3)); UNIT_ASSERT_VALUES_EQUAL((++it)->ToString(), TString(headerLine4)); - } + } Y_UNIT_TEST(ContentLengthRemoval) { TMemoryInput request("GET / HTTP/1.1\r\nAccept-Encoding: gzip\r\n\r\n"); @@ -430,8 +430,8 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { httpOut.EnableCompression(true); httpOut << "HTTP/1.1 200 OK\r\n"; char answer[] = "Mary had a little lamb."; - httpOut << "Content-Length: " << strlen(answer) << "\r\n" - "\r\n"; + httpOut << "Content-Length: " << strlen(answer) << "\r\n" + "\r\n"; httpOut << answer; httpOut.Finish(); @@ -541,9 +541,9 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { TStringStream request; { THttpOutput httpOutput(&request); - httpOutput << "POST / HTTP/1.1\r\n" - "Host: yandex.ru\r\n" - "\r\n"; + httpOutput << "POST / HTTP/1.1\r\n" + "Host: yandex.ru\r\n" + "\r\n"; httpOutput << "GGLOL"; } { @@ -568,9 +568,9 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { Y_UNIT_TEST(TestInputHasContent) { { TStringStream request; - request << "POST / HTTP/1.1\r\n" - "Host: yandex.ru\r\n" - "\r\n"; + request << "POST / HTTP/1.1\r\n" + "Host: yandex.ru\r\n" + "\r\n"; request << "HTTPDATA"; TStringInput input(request.Str()); @@ -582,10 +582,10 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { { TStringStream request; - request << "POST / HTTP/1.1\r\n" - "Host: yandex.ru\r\n" - "Content-Length: 8" - "\r\n\r\n"; + request << "POST / HTTP/1.1\r\n" + "Host: yandex.ru\r\n" + "Content-Length: 8" + "\r\n\r\n"; request << "HTTPDATA"; TStringInput input(request.Str()); @@ -597,10 +597,10 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { { TStringStream request; - request << "POST / HTTP/1.1\r\n" - "Host: yandex.ru\r\n" - "Transfer-Encoding: chunked" - "\r\n\r\n"; + request << "POST / HTTP/1.1\r\n" + "Host: yandex.ru\r\n" + "Transfer-Encoding: chunked" + "\r\n\r\n"; request << "8\r\nHTTPDATA\r\n0\r\n"; TStringInput input(request.Str()); @@ -612,10 +612,10 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { } Y_UNIT_TEST(TestHttpInputHeadRequest) { - class THeadOnlyInput: public IInputStream { + class THeadOnlyInput: public IInputStream { public: THeadOnlyInput() = default; - + private: size_t DoRead(void* buf, size_t len) override { if (Eof_) { @@ -635,8 +635,8 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { private: TString Data_{TStringBuf("HEAD / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n")}; - size_t Pos_{0}; - bool Eof_{false}; + size_t Pos_{0}; + bool Eof_{false}; }; THeadOnlyInput input; THttpInput httpInput(&input); @@ -647,10 +647,10 @@ Y_UNIT_TEST_SUITE(THttpStreamTest) { Y_UNIT_TEST(TestHttpOutputResponseToHeadRequestNoZeroChunk) { TStringStream request; - request << "HEAD / HTTP/1.1\r\n" - "Host: yandex.ru\r\n" - "Connection: Keep-Alive\r\n" - "\r\n"; + request << "HEAD / HTTP/1.1\r\n" + "Host: yandex.ru\r\n" + "Connection: Keep-Alive\r\n" + "\r\n"; TStringInput input(request.Str()); THttpInput httpInput(&input); diff --git a/library/cpp/http/io/stream_ut_medium.cpp b/library/cpp/http/io/stream_ut_medium.cpp index e70d47555d..2c125eb21e 100644 --- a/library/cpp/http/io/stream_ut_medium.cpp +++ b/library/cpp/http/io/stream_ut_medium.cpp @@ -1,54 +1,54 @@ -#include "stream.h" +#include "stream.h" #include <library/cpp/testing/unittest/registar.h> -#include <util/stream/zlib.h> - +#include <util/stream/zlib.h> + Y_UNIT_TEST_SUITE(THttpTestMedium) { Y_UNIT_TEST(TestCodings2) { - TStringBuf data = "aaaaaaaaaaaaaaaaaaaaaaa"; - - for (auto codec : SupportedCodings()) { + TStringBuf data = "aaaaaaaaaaaaaaaaaaaaaaa"; + + for (auto codec : SupportedCodings()) { if (codec == TStringBuf("z-zlib-0")) { - continue; - } - + continue; + } + if (codec == TStringBuf("z-null")) { - continue; - } - - TString s; - - { - TStringOutput so(s); - THttpOutput ho(&so); - TBufferedOutput bo(&ho, 10000); - - bo << "HTTP/1.1 200 Ok\r\n" - << "Connection: close\r\n" - << "Content-Encoding: " << codec << "\r\n\r\n"; - - for (size_t i = 0; i < 100; ++i) { - bo << data; - } - } - - try { + continue; + } + + TString s; + + { + TStringOutput so(s); + THttpOutput ho(&so); + TBufferedOutput bo(&ho, 10000); + + bo << "HTTP/1.1 200 Ok\r\n" + << "Connection: close\r\n" + << "Content-Encoding: " << codec << "\r\n\r\n"; + + for (size_t i = 0; i < 100; ++i) { + bo << data; + } + } + + try { UNIT_ASSERT(s.size() > 10); - UNIT_ASSERT(s.find(data) == TString::npos); - } catch (...) { - Cerr << codec << " " << s << Endl; - - throw; - } - - { - TStringInput si(s); - THttpInput hi(&si); - - auto res = hi.ReadAll(); - - UNIT_ASSERT(res.find(data) == 0); - } - } - } - + UNIT_ASSERT(s.find(data) == TString::npos); + } catch (...) { + Cerr << codec << " " << s << Endl; + + throw; + } + + { + TStringInput si(s); + THttpInput hi(&si); + + auto res = hi.ReadAll(); + + UNIT_ASSERT(res.find(data) == 0); + } + } + } + } // THttpTestMedium suite diff --git a/library/cpp/http/io/ut/medium/ya.make b/library/cpp/http/io/ut/medium/ya.make index 24d16b00ea..235a23dcd7 100644 --- a/library/cpp/http/io/ut/medium/ya.make +++ b/library/cpp/http/io/ut/medium/ya.make @@ -1,11 +1,11 @@ UNITTEST_FOR(library/cpp/http/io) - + SIZE(MEDIUM) OWNER(g:util) - -SRCS( + +SRCS( stream_ut_medium.cpp -) - -END() +) + +END() diff --git a/library/cpp/http/io/ut/ya.make b/library/cpp/http/io/ut/ya.make index ea0597ebb6..84f6949db3 100644 --- a/library/cpp/http/io/ut/ya.make +++ b/library/cpp/http/io/ut/ya.make @@ -1,16 +1,16 @@ UNITTEST_FOR(library/cpp/http/io) - + OWNER(g:util) - + PEERDIR( library/cpp/http/server ) -SRCS( - chunk_ut.cpp +SRCS( + chunk_ut.cpp compression_ut.cpp headers_ut.cpp - stream_ut.cpp -) - -END() + stream_ut.cpp +) + +END() diff --git a/library/cpp/http/io/ya.make b/library/cpp/http/io/ya.make index 83b30c8958..dcfbd79885 100644 --- a/library/cpp/http/io/ya.make +++ b/library/cpp/http/io/ya.make @@ -1,22 +1,22 @@ -LIBRARY() - +LIBRARY() + OWNER( g:util mvel ) - -PEERDIR( + +PEERDIR( library/cpp/blockcodecs library/cpp/streams/brotli library/cpp/streams/bzip2 library/cpp/streams/lzma -) - -SRCS( - chunk.cpp +) + +SRCS( + chunk.cpp compression.cpp - headers.cpp + headers.cpp stream.cpp -) - -END() +) + +END() diff --git a/library/cpp/http/misc/httpcodes.cpp b/library/cpp/http/misc/httpcodes.cpp index fb9e43c9d3..ad8c80ac1e 100644 --- a/library/cpp/http/misc/httpcodes.cpp +++ b/library/cpp/http/misc/httpcodes.cpp @@ -2,26 +2,26 @@ TStringBuf HttpCodeStrEx(int code) noexcept { switch (code) { - case HTTP_CONTINUE: + case HTTP_CONTINUE: return TStringBuf("100 Continue"); - case HTTP_SWITCHING_PROTOCOLS: + case HTTP_SWITCHING_PROTOCOLS: return TStringBuf("101 Switching protocols"); case HTTP_PROCESSING: return TStringBuf("102 Processing"); - - case HTTP_OK: + + case HTTP_OK: return TStringBuf("200 Ok"); - case HTTP_CREATED: + case HTTP_CREATED: return TStringBuf("201 Created"); - case HTTP_ACCEPTED: + case HTTP_ACCEPTED: return TStringBuf("202 Accepted"); - case HTTP_NON_AUTHORITATIVE_INFORMATION: + case HTTP_NON_AUTHORITATIVE_INFORMATION: return TStringBuf("203 None authoritative information"); - case HTTP_NO_CONTENT: + case HTTP_NO_CONTENT: return TStringBuf("204 No content"); - case HTTP_RESET_CONTENT: + case HTTP_RESET_CONTENT: return TStringBuf("205 Reset content"); - case HTTP_PARTIAL_CONTENT: + case HTTP_PARTIAL_CONTENT: return TStringBuf("206 Partial content"); case HTTP_MULTI_STATUS: return TStringBuf("207 Multi status"); @@ -30,58 +30,58 @@ TStringBuf HttpCodeStrEx(int code) noexcept { case HTTP_IM_USED: return TStringBuf("226 IM used"); - case HTTP_MULTIPLE_CHOICES: + case HTTP_MULTIPLE_CHOICES: return TStringBuf("300 Multiple choices"); - case HTTP_MOVED_PERMANENTLY: + case HTTP_MOVED_PERMANENTLY: return TStringBuf("301 Moved permanently"); - case HTTP_FOUND: + case HTTP_FOUND: return TStringBuf("302 Moved temporarily"); - case HTTP_SEE_OTHER: + case HTTP_SEE_OTHER: return TStringBuf("303 See other"); - case HTTP_NOT_MODIFIED: + case HTTP_NOT_MODIFIED: return TStringBuf("304 Not modified"); - case HTTP_USE_PROXY: + case HTTP_USE_PROXY: return TStringBuf("305 Use proxy"); - case HTTP_TEMPORARY_REDIRECT: + case HTTP_TEMPORARY_REDIRECT: return TStringBuf("307 Temporarily redirect"); case HTTP_PERMANENT_REDIRECT: return TStringBuf("308 Permanent redirect"); - case HTTP_BAD_REQUEST: + case HTTP_BAD_REQUEST: return TStringBuf("400 Bad request"); - case HTTP_UNAUTHORIZED: + case HTTP_UNAUTHORIZED: return TStringBuf("401 Unauthorized"); - case HTTP_PAYMENT_REQUIRED: + case HTTP_PAYMENT_REQUIRED: return TStringBuf("402 Payment required"); - case HTTP_FORBIDDEN: + case HTTP_FORBIDDEN: return TStringBuf("403 Forbidden"); - case HTTP_NOT_FOUND: + case HTTP_NOT_FOUND: return TStringBuf("404 Not found"); - case HTTP_METHOD_NOT_ALLOWED: + case HTTP_METHOD_NOT_ALLOWED: return TStringBuf("405 Method not allowed"); - case HTTP_NOT_ACCEPTABLE: + case HTTP_NOT_ACCEPTABLE: return TStringBuf("406 Not acceptable"); - case HTTP_PROXY_AUTHENTICATION_REQUIRED: + case HTTP_PROXY_AUTHENTICATION_REQUIRED: return TStringBuf("407 Proxy Authentication required"); - case HTTP_REQUEST_TIME_OUT: + case HTTP_REQUEST_TIME_OUT: return TStringBuf("408 Request time out"); - case HTTP_CONFLICT: + case HTTP_CONFLICT: return TStringBuf("409 Conflict"); - case HTTP_GONE: + case HTTP_GONE: return TStringBuf("410 Gone"); - case HTTP_LENGTH_REQUIRED: + case HTTP_LENGTH_REQUIRED: return TStringBuf("411 Length required"); - case HTTP_PRECONDITION_FAILED: + case HTTP_PRECONDITION_FAILED: return TStringBuf("412 Precondition failed"); - case HTTP_REQUEST_ENTITY_TOO_LARGE: + case HTTP_REQUEST_ENTITY_TOO_LARGE: return TStringBuf("413 Request entity too large"); - case HTTP_REQUEST_URI_TOO_LARGE: + case HTTP_REQUEST_URI_TOO_LARGE: return TStringBuf("414 Request uri too large"); - case HTTP_UNSUPPORTED_MEDIA_TYPE: + case HTTP_UNSUPPORTED_MEDIA_TYPE: return TStringBuf("415 Unsupported media type"); - case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: + case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: return TStringBuf("416 Requested Range Not Satisfiable"); - case HTTP_EXPECTATION_FAILED: + case HTTP_EXPECTATION_FAILED: return TStringBuf("417 Expectation Failed"); case HTTP_I_AM_A_TEAPOT: return TStringBuf("418 I Am A Teapot"); @@ -89,7 +89,7 @@ TStringBuf HttpCodeStrEx(int code) noexcept { return TStringBuf("419 Authentication Timeout"); case HTTP_MISDIRECTED_REQUEST: return TStringBuf("421 Misdirected Request"); - case HTTP_UNPROCESSABLE_ENTITY: + case HTTP_UNPROCESSABLE_ENTITY: return TStringBuf("422 Unprocessable Entity"); case HTTP_LOCKED: return TStringBuf("423 Locked"); @@ -101,24 +101,24 @@ TStringBuf HttpCodeStrEx(int code) noexcept { return TStringBuf("426 Upgrade Required"); case HTTP_PRECONDITION_REQUIRED: return TStringBuf("428 Precondition Required"); - case HTTP_TOO_MANY_REQUESTS: + case HTTP_TOO_MANY_REQUESTS: return TStringBuf("429 Too Many Requests"); case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: return TStringBuf("431 Request Header Fields Too Large"); case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: return TStringBuf("451 Unavailable For Legal Reason"); - case HTTP_INTERNAL_SERVER_ERROR: + case HTTP_INTERNAL_SERVER_ERROR: return TStringBuf("500 Internal server error"); - case HTTP_NOT_IMPLEMENTED: + case HTTP_NOT_IMPLEMENTED: return TStringBuf("501 Not implemented"); - case HTTP_BAD_GATEWAY: + case HTTP_BAD_GATEWAY: return TStringBuf("502 Bad gateway"); - case HTTP_SERVICE_UNAVAILABLE: + case HTTP_SERVICE_UNAVAILABLE: return TStringBuf("503 Service unavailable"); - case HTTP_GATEWAY_TIME_OUT: + case HTTP_GATEWAY_TIME_OUT: return TStringBuf("504 Gateway time out"); - case HTTP_HTTP_VERSION_NOT_SUPPORTED: + case HTTP_HTTP_VERSION_NOT_SUPPORTED: return TStringBuf("505 HTTP version not supported"); case HTTP_VARIANT_ALSO_NEGOTIATES: return TStringBuf("506 Variant also negotiates"); @@ -135,7 +135,7 @@ TStringBuf HttpCodeStrEx(int code) noexcept { case HTTP_UNASSIGNED_512: return TStringBuf("512 Unassigned"); - default: + default: return TStringBuf("000 Unknown HTTP code"); } } diff --git a/library/cpp/http/misc/httpcodes.h b/library/cpp/http/misc/httpcodes.h index 2b7a3c4a80..cbfbaa1188 100644 --- a/library/cpp/http/misc/httpcodes.h +++ b/library/cpp/http/misc/httpcodes.h @@ -3,67 +3,67 @@ #include <util/generic/strbuf.h> enum HttpCodes { - HTTP_CONTINUE = 100, - HTTP_SWITCHING_PROTOCOLS = 101, + HTTP_CONTINUE = 100, + HTTP_SWITCHING_PROTOCOLS = 101, HTTP_PROCESSING = 102, - HTTP_OK = 200, - HTTP_CREATED = 201, - HTTP_ACCEPTED = 202, - HTTP_NON_AUTHORITATIVE_INFORMATION = 203, - HTTP_NO_CONTENT = 204, - HTTP_RESET_CONTENT = 205, - HTTP_PARTIAL_CONTENT = 206, + HTTP_OK = 200, + HTTP_CREATED = 201, + HTTP_ACCEPTED = 202, + HTTP_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_NO_CONTENT = 204, + HTTP_RESET_CONTENT = 205, + HTTP_PARTIAL_CONTENT = 206, HTTP_MULTI_STATUS = 207, HTTP_ALREADY_REPORTED = 208, HTTP_IM_USED = 226, - HTTP_MULTIPLE_CHOICES = 300, - HTTP_MOVED_PERMANENTLY = 301, - HTTP_FOUND = 302, - HTTP_SEE_OTHER = 303, - HTTP_NOT_MODIFIED = 304, - HTTP_USE_PROXY = 305, - HTTP_TEMPORARY_REDIRECT = 307, + HTTP_MULTIPLE_CHOICES = 300, + HTTP_MOVED_PERMANENTLY = 301, + HTTP_FOUND = 302, + HTTP_SEE_OTHER = 303, + HTTP_NOT_MODIFIED = 304, + HTTP_USE_PROXY = 305, + HTTP_TEMPORARY_REDIRECT = 307, HTTP_PERMANENT_REDIRECT = 308, - HTTP_BAD_REQUEST = 400, - HTTP_UNAUTHORIZED = 401, - HTTP_PAYMENT_REQUIRED = 402, - HTTP_FORBIDDEN = 403, - HTTP_NOT_FOUND = 404, - HTTP_METHOD_NOT_ALLOWED = 405, - HTTP_NOT_ACCEPTABLE = 406, - HTTP_PROXY_AUTHENTICATION_REQUIRED = 407, - HTTP_REQUEST_TIME_OUT = 408, - HTTP_CONFLICT = 409, - HTTP_GONE = 410, - HTTP_LENGTH_REQUIRED = 411, - HTTP_PRECONDITION_FAILED = 412, - HTTP_REQUEST_ENTITY_TOO_LARGE = 413, - HTTP_REQUEST_URI_TOO_LARGE = 414, - HTTP_UNSUPPORTED_MEDIA_TYPE = 415, - HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416, - HTTP_EXPECTATION_FAILED = 417, + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_PAYMENT_REQUIRED = 402, + HTTP_FORBIDDEN = 403, + HTTP_NOT_FOUND = 404, + HTTP_METHOD_NOT_ALLOWED = 405, + HTTP_NOT_ACCEPTABLE = 406, + HTTP_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_REQUEST_TIME_OUT = 408, + HTTP_CONFLICT = 409, + HTTP_GONE = 410, + HTTP_LENGTH_REQUIRED = 411, + HTTP_PRECONDITION_FAILED = 412, + HTTP_REQUEST_ENTITY_TOO_LARGE = 413, + HTTP_REQUEST_URI_TOO_LARGE = 414, + HTTP_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416, + HTTP_EXPECTATION_FAILED = 417, HTTP_I_AM_A_TEAPOT = 418, HTTP_AUTHENTICATION_TIMEOUT = 419, HTTP_MISDIRECTED_REQUEST = 421, - HTTP_UNPROCESSABLE_ENTITY = 422, + HTTP_UNPROCESSABLE_ENTITY = 422, HTTP_LOCKED = 423, HTTP_FAILED_DEPENDENCY = 424, HTTP_UNORDERED_COLLECTION = 425, HTTP_UPGRADE_REQUIRED = 426, HTTP_PRECONDITION_REQUIRED = 428, - HTTP_TOO_MANY_REQUESTS = 429, + HTTP_TOO_MANY_REQUESTS = 429, HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451, - HTTP_INTERNAL_SERVER_ERROR = 500, - HTTP_NOT_IMPLEMENTED = 501, - HTTP_BAD_GATEWAY = 502, - HTTP_SERVICE_UNAVAILABLE = 503, - HTTP_GATEWAY_TIME_OUT = 504, - HTTP_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_INTERNAL_SERVER_ERROR = 500, + HTTP_NOT_IMPLEMENTED = 501, + HTTP_BAD_GATEWAY = 502, + HTTP_SERVICE_UNAVAILABLE = 503, + HTTP_GATEWAY_TIME_OUT = 504, + HTTP_HTTP_VERSION_NOT_SUPPORTED = 505, HTTP_VARIANT_ALSO_NEGOTIATES = 506, HTTP_INSUFFICIENT_STORAGE = 507, HTTP_LOOP_DETECTED = 508, diff --git a/library/cpp/http/misc/httpdate.cpp b/library/cpp/http/misc/httpdate.cpp index 98876293c6..4a3031bbf4 100644 --- a/library/cpp/http/misc/httpdate.cpp +++ b/library/cpp/http/misc/httpdate.cpp @@ -43,7 +43,7 @@ static const char *wkdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; - + static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" @@ -64,15 +64,15 @@ int format_http_date(char buf[], size_t size, time_t when) { #endif } -char* format_http_date(time_t when, char* buf, size_t buflen) { - const int len = format_http_date(buf, buflen, when); - - if (len == 0) { +char* format_http_date(time_t when, char* buf, size_t buflen) { + const int len = format_http_date(buf, buflen, when); + + if (len == 0) { return nullptr; - } - + } + Y_ASSERT(len > 0 && size_t(len) < buflen); - + return buf; } diff --git a/library/cpp/http/misc/httpdate.h b/library/cpp/http/misc/httpdate.h index 0640624661..04876f38fe 100644 --- a/library/cpp/http/misc/httpdate.h +++ b/library/cpp/http/misc/httpdate.h @@ -1,11 +1,11 @@ #pragma once -#include <util/datetime/base.h> +#include <util/datetime/base.h> #include <util/generic/string.h> - + #include <ctime> -#define BAD_DATE ((time_t)-1) +#define BAD_DATE ((time_t)-1) inline time_t parse_http_date(const TStringBuf& datestring) { try { @@ -16,6 +16,6 @@ inline time_t parse_http_date(const TStringBuf& datestring) { } int format_http_date(char buf[], size_t size, time_t when); -char* format_http_date(time_t when, char* buf, size_t len); +char* format_http_date(time_t when, char* buf, size_t len); TString FormatHttpDate(time_t when); diff --git a/library/cpp/http/misc/httpdate_ut.cpp b/library/cpp/http/misc/httpdate_ut.cpp index ac4e54063e..c1a0103501 100644 --- a/library/cpp/http/misc/httpdate_ut.cpp +++ b/library/cpp/http/misc/httpdate_ut.cpp @@ -1,15 +1,15 @@ #include <library/cpp/testing/unittest/registar.h> - -#include "httpdate.h" - + +#include "httpdate.h" + Y_UNIT_TEST_SUITE(TestHttpDate) { Y_UNIT_TEST(Test1) { - char buf1[100]; - char buf2[100]; - - UNIT_ASSERT((int)strlen(format_http_date(0, buf1, sizeof(buf1))) == format_http_date(buf2, sizeof(buf2), 0)); - } + char buf1[100]; + char buf2[100]; + + UNIT_ASSERT((int)strlen(format_http_date(0, buf1, sizeof(buf1))) == format_http_date(buf2, sizeof(buf2), 0)); + } Y_UNIT_TEST(Test2) { UNIT_ASSERT_STRINGS_EQUAL(FormatHttpDate(1234567890), "Fri, 13 Feb 2009 23:31:30 GMT"); } -} +} diff --git a/library/cpp/http/misc/httpreqdata.cpp b/library/cpp/http/misc/httpreqdata.cpp index ecc55e754d..f6951f68cd 100644 --- a/library/cpp/http/misc/httpreqdata.cpp +++ b/library/cpp/http/misc/httpreqdata.cpp @@ -1,51 +1,51 @@ -#include "httpreqdata.h" - +#include "httpreqdata.h" + #include <util/stream/mem.h> TBaseServerRequestData::TBaseServerRequestData(SOCKET s) : Addr(nullptr) - , Host() - , Port() + , Host() + , Port() , Path(nullptr) , Search(nullptr) - , SearchLength(0) - , Socket(s) - , BeginTime(MicroSeconds()) -{ -} - + , SearchLength(0) + , Socket(s) + , BeginTime(MicroSeconds()) +{ +} + TBaseServerRequestData::TBaseServerRequestData(const char* qs, SOCKET s) : Addr(nullptr) - , Host() - , Port() + , Host() + , Port() , Path(nullptr) - , Search((char*)qs) - , SearchLength(qs ? strlen(qs) : 0) + , Search((char*)qs) + , SearchLength(qs ? strlen(qs) : 0) , OrigSearch(Search, SearchLength) - , Socket(s) - , BeginTime(MicroSeconds()) -{ -} - + , Socket(s) + , BeginTime(MicroSeconds()) +{ +} + void TBaseServerRequestData::AppendQueryString(const char* str, size_t length) { - if (Y_UNLIKELY(Search)) { + if (Y_UNLIKELY(Search)) { Y_ASSERT(strlen(Search) == SearchLength); ModifiedQueryString.Reserve(SearchLength + length + 2); ModifiedQueryString.Assign(Search, SearchLength); - if (SearchLength > 0 && Search[SearchLength - 1] != '&' && - length > 0 && str[0] != '&') { + if (SearchLength > 0 && Search[SearchLength - 1] != '&' && + length > 0 && str[0] != '&') { ModifiedQueryString.Append('&'); - } + } ModifiedQueryString.Append(str, length); - } else { + } else { ModifiedQueryString.Reserve(length + 1); ModifiedQueryString.Assign(str, length); - } + } ModifiedQueryString.Append('\0'); Search = ModifiedQueryString.data(); SearchLength = ModifiedQueryString.size() - 1; // ignore terminator -} - +} + void TBaseServerRequestData::SetRemoteAddr(TStringBuf addr) { TMemoryOutput out(AddrData, Y_ARRAY_SIZE(AddrData) - 1); out.Write(addr.substr(0, Y_ARRAY_SIZE(AddrData) - 1)); @@ -55,142 +55,142 @@ void TBaseServerRequestData::SetRemoteAddr(TStringBuf addr) { } const char* TBaseServerRequestData::RemoteAddr() const { - if (!Addr) { - *AddrData = 0; - GetRemoteAddr(Socket, AddrData, sizeof(AddrData)); - Addr = AddrData; - } - - return Addr; -} - + if (!Addr) { + *AddrData = 0; + GetRemoteAddr(Socket, AddrData, sizeof(AddrData)); + Addr = AddrData; + } + + return Addr; +} + const char* TBaseServerRequestData::HeaderIn(TStringBuf key) const { auto it = HeadersIn_.find(key); - + if (it == HeadersIn_.end()) { return nullptr; - } - + } + return it->second.data(); -} - +} + TString TBaseServerRequestData::HeaderByIndex(size_t n) const noexcept { - if (n >= HeadersCount()) { + if (n >= HeadersCount()) { return nullptr; - } - + } + THttpHeadersContainer::const_iterator i = HeadersIn_.begin(); - - while (n) { - ++i; - --n; - } - + + while (n) { + ++i; + --n; + } + return TString(i->first) + TStringBuf(": ") + i->second; -} - +} + const char* TBaseServerRequestData::Environment(const char* key) const { - if (stricmp(key, "REMOTE_ADDR") == 0) { - const char* ip = HeaderIn("X-Real-IP"); - if (ip) - return ip; - return RemoteAddr(); - } else if (stricmp(key, "QUERY_STRING") == 0) { - return QueryString(); - } else if (stricmp(key, "SERVER_NAME") == 0) { + if (stricmp(key, "REMOTE_ADDR") == 0) { + const char* ip = HeaderIn("X-Real-IP"); + if (ip) + return ip; + return RemoteAddr(); + } else if (stricmp(key, "QUERY_STRING") == 0) { + return QueryString(); + } else if (stricmp(key, "SERVER_NAME") == 0) { return ServerName().data(); - } else if (stricmp(key, "SERVER_PORT") == 0) { + } else if (stricmp(key, "SERVER_PORT") == 0) { return ServerPort().data(); - } else if (stricmp(key, "SCRIPT_NAME") == 0) { - return ScriptName(); - } + } else if (stricmp(key, "SCRIPT_NAME") == 0) { + return ScriptName(); + } return nullptr; -} - +} + void TBaseServerRequestData::Clear() { HeadersIn_.clear(); Addr = Path = Search = nullptr; OrigSearch = {}; - SearchLength = 0; - Host.clear(); - Port.clear(); - CurPage.remove(); + SearchLength = 0; + Host.clear(); + Port.clear(); + CurPage.remove(); ParseBuf.Clear(); - BeginTime = MicroSeconds(); -} - + BeginTime = MicroSeconds(); +} + const char* TBaseServerRequestData::GetCurPage() const { - if (!CurPage && Host) { - CurPage = "http://"; - CurPage += Host; - if (Port) { - CurPage += ':'; - CurPage += Port; - } - CurPage += Path; - if (Search) { - CurPage += '?'; - CurPage += Search; - } - } + if (!CurPage && Host) { + CurPage = "http://"; + CurPage += Host; + if (Port) { + CurPage += ':'; + CurPage += Port; + } + CurPage += Path; + if (Search) { + CurPage += '?'; + CurPage += Search; + } + } return CurPage.data(); -} - +} + bool TBaseServerRequestData::Parse(const char* origReq) { - size_t origReqLength = strlen(origReq); + size_t origReqLength = strlen(origReq); ParseBuf.Assign(origReq, origReqLength + 1); char* req = ParseBuf.Data(); - - while (*req == ' ' || *req == '\t') - req++; - if (*req != '/') - return false; // we are not a proxy - while (req[1] == '/') // remove redundant slashes - req++; - - // detect url end (can contain some garbage after whitespace, e.g. 'HTTP 1.1') - char* urlEnd = req; - while (*urlEnd && *urlEnd != ' ' && *urlEnd != '\t') - urlEnd++; - if (*urlEnd) - *urlEnd = 0; - - // cut fragment if exists - char* fragment = strchr(req, '#'); - if (fragment) - *fragment = 0; // ignore fragment - else - fragment = urlEnd; - Path = req; - - // calculate Search length without additional strlen-ing - Search = strchr(Path, '?'); - if (Search) { - *Search++ = 0; - ptrdiff_t delta = fragment - Search; - // indeed, second case is a parse error - SearchLength = (delta >= 0) ? delta : (urlEnd - Search); + + while (*req == ' ' || *req == '\t') + req++; + if (*req != '/') + return false; // we are not a proxy + while (req[1] == '/') // remove redundant slashes + req++; + + // detect url end (can contain some garbage after whitespace, e.g. 'HTTP 1.1') + char* urlEnd = req; + while (*urlEnd && *urlEnd != ' ' && *urlEnd != '\t') + urlEnd++; + if (*urlEnd) + *urlEnd = 0; + + // cut fragment if exists + char* fragment = strchr(req, '#'); + if (fragment) + *fragment = 0; // ignore fragment + else + fragment = urlEnd; + Path = req; + + // calculate Search length without additional strlen-ing + Search = strchr(Path, '?'); + if (Search) { + *Search++ = 0; + ptrdiff_t delta = fragment - Search; + // indeed, second case is a parse error + SearchLength = (delta >= 0) ? delta : (urlEnd - Search); Y_ASSERT(strlen(Search) == SearchLength); - } else { - SearchLength = 0; - } + } else { + SearchLength = 0; + } OrigSearch = {Search, SearchLength}; - return true; -} - + return true; +} + void TBaseServerRequestData::AddHeader(const TString& name, const TString& value) { HeadersIn_[name] = value; - + if (stricmp(name.data(), "Host") == 0) { size_t hostLen = strcspn(value.data(), ":"); if (value[hostLen] == ':') Port = value.substr(hostLen + 1); Host = value.substr(0, hostLen); - } -} - + } +} + void TBaseServerRequestData::SetPath(const TString& path) { PathStorage = TBuffer(path.data(), path.size() + 1); Path = PathStorage.Data(); -} +} diff --git a/library/cpp/http/misc/httpreqdata.h b/library/cpp/http/misc/httpreqdata.h index 946a0e5f14..16e59c4d78 100644 --- a/library/cpp/http/misc/httpreqdata.h +++ b/library/cpp/http/misc/httpreqdata.h @@ -1,14 +1,14 @@ #pragma once #include <library/cpp/digest/lower_case/hash_ops.h> - -#include <util/str_stl.h> - + +#include <util/str_stl.h> + #include <util/system/defaults.h> -#include <util/string/cast.h> +#include <util/string/cast.h> #include <library/cpp/cgiparam/cgiparam.h> #include <util/network/address.h> -#include <util/network/socket.h> +#include <util/network/socket.h> #include <util/generic/hash.h> #include <util/system/yassert.h> #include <util/generic/string.h> @@ -21,16 +21,16 @@ class TBaseServerRequestData { public: TBaseServerRequestData(SOCKET s = INVALID_SOCKET); TBaseServerRequestData(const char* qs, SOCKET s = INVALID_SOCKET); - + void SetHost(const TString& host, ui16 port) { Host = host; Port = ToString(port); } - + const TString& ServerName() const { return Host; } - + NAddr::IRemoteAddrPtr ServerAddress() const { return NAddr::GetSockAddr(Socket); } @@ -38,57 +38,57 @@ public: const TString& ServerPort() const { return Port; } - + const char* ScriptName() const { return Path; } - + const char* QueryString() const { return Search; } - + TStringBuf QueryStringBuf() const { return TStringBuf(Search, SearchLength); } - + TStringBuf OrigQueryStringBuf() const { return OrigSearch; } - void AppendQueryString(const char* str, size_t length); - const char* RemoteAddr() const; + void AppendQueryString(const char* str, size_t length); + const char* RemoteAddr() const; void SetRemoteAddr(TStringBuf addr); const char* HeaderIn(TStringBuf key) const; - + const THttpHeadersContainer& HeadersIn() const { return HeadersIn_; } inline size_t HeadersCount() const noexcept { return HeadersIn_.size(); - } - + } + TString HeaderByIndex(size_t n) const noexcept; - const char* Environment(const char* key) const; - - void Clear(); - + const char* Environment(const char* key) const; + + void Clear(); + void SetSocket(SOCKET s) noexcept { - Socket = s; - } - + Socket = s; + } + ui64 RequestBeginTime() const noexcept { - return BeginTime; - } - + return BeginTime; + } + void SetPath(const TString& path); const char* GetCurPage() const; bool Parse(const char* req); void AddHeader(const TString& name, const TString& value); - + private: TBuffer PathStorage; - mutable char* Addr; + mutable char* Addr; TString Host; TString Port; char* Path; @@ -98,13 +98,13 @@ private: THttpHeadersContainer HeadersIn_; mutable char AddrData[INET6_ADDRSTRLEN]; SOCKET Socket; - ui64 BeginTime; + ui64 BeginTime; mutable TString CurPage; TBuffer ParseBuf; TBuffer ModifiedQueryString; }; - -class TServerRequestData: public TBaseServerRequestData { + +class TServerRequestData: public TBaseServerRequestData { public: TServerRequestData(SOCKET s = INVALID_SOCKET) : TBaseServerRequestData(s) @@ -119,7 +119,7 @@ public: void Scan() { CgiParam.Scan(QueryStringBuf()); } - + public: - TCgiParameters CgiParam; + TCgiParameters CgiParam; }; diff --git a/library/cpp/http/misc/httpreqdata_ut.cpp b/library/cpp/http/misc/httpreqdata_ut.cpp index 24225e78ac..e7f16ef27c 100644 --- a/library/cpp/http/misc/httpreqdata_ut.cpp +++ b/library/cpp/http/misc/httpreqdata_ut.cpp @@ -4,19 +4,19 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) { Y_UNIT_TEST(Headers) { - TServerRequestData sd; - + TServerRequestData sd; + sd.AddHeader("x-xx", "y-yy"); sd.AddHeader("x-Xx", "y-yy"); - - UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 1); - + + UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 1); + sd.AddHeader("x-XxX", "y-yyy"); - UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2); + UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2); UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XX")), TStringBuf("y-yy")); UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XXX")), TStringBuf("y-yyy")); - } - + } + Y_UNIT_TEST(ComplexHeaders) { TServerRequestData sd; sd.SetHost("zzz", 1); @@ -43,24 +43,24 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) { } Y_UNIT_TEST(ParseScan) { - TServerRequestData rd; + TServerRequestData rd; - // Parse parses url without host - UNIT_ASSERT(!rd.Parse(" http://yandex.ru/yandsearch?>a=fake&haha=da HTTP 1.1 OK")); + // Parse parses url without host + UNIT_ASSERT(!rd.Parse(" http://yandex.ru/yandsearch?>a=fake&haha=da HTTP 1.1 OK")); - // This should work - UNIT_ASSERT(rd.Parse(" /yandsearch?>a=fake&haha=da HTTP 1.1 OK")); + // This should work + UNIT_ASSERT(rd.Parse(" /yandsearch?>a=fake&haha=da HTTP 1.1 OK")); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ">a=fake&haha=da"); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf()); - rd.Scan(); - UNIT_ASSERT(rd.CgiParam.Has("gta", "fake")); - UNIT_ASSERT(rd.CgiParam.Has("haha", "da")); - UNIT_ASSERT(!rd.CgiParam.Has("no-param")); + rd.Scan(); + UNIT_ASSERT(rd.CgiParam.Has("gta", "fake")); + UNIT_ASSERT(rd.CgiParam.Has("haha", "da")); + UNIT_ASSERT(!rd.CgiParam.Has("no-param")); - rd.Clear(); - } + rd.Clear(); + } Y_UNIT_TEST(Ctor) { const TString qs("gta=fake&haha=da"); @@ -69,55 +69,55 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) { UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); - UNIT_ASSERT(rd.CgiParam.Has("gta")); - UNIT_ASSERT(rd.CgiParam.Has("haha")); - UNIT_ASSERT(!rd.CgiParam.Has("no-param")); - } + UNIT_ASSERT(rd.CgiParam.Has("gta")); + UNIT_ASSERT(rd.CgiParam.Has("haha")); + UNIT_ASSERT(!rd.CgiParam.Has("no-param")); + } Y_UNIT_TEST(HashCut) { const TString qs(">a=fake&haha=da"); const TString header = " /yandsearch?" + qs + "#&uberParam=yes&q=? HTTP 1.1 OK"; - TServerRequestData rd; + TServerRequestData rd; rd.Parse(header.c_str()); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); - rd.Scan(); - UNIT_ASSERT(rd.CgiParam.Has("gta")); - UNIT_ASSERT(rd.CgiParam.Has("haha")); - UNIT_ASSERT(!rd.CgiParam.Has("uberParam")); - } + rd.Scan(); + UNIT_ASSERT(rd.CgiParam.Has("gta")); + UNIT_ASSERT(rd.CgiParam.Has("haha")); + UNIT_ASSERT(!rd.CgiParam.Has("uberParam")); + } Y_UNIT_TEST(MisplacedHashCut) { - TServerRequestData rd; - rd.Parse(" /y#ndsearch?>a=fake&haha=da&uberParam=yes&q=? HTTP 1.1 OK"); + TServerRequestData rd; + rd.Parse(" /y#ndsearch?>a=fake&haha=da&uberParam=yes&q=? HTTP 1.1 OK"); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ""); UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), ""); - rd.Scan(); - UNIT_ASSERT(rd.CgiParam.empty()); - } + rd.Scan(); + UNIT_ASSERT(rd.CgiParam.empty()); + } Y_UNIT_TEST(CornerCase) { - TServerRequestData rd; - rd.Parse(" /yandsearch?#"); + TServerRequestData rd; + rd.Parse(" /yandsearch?#"); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ""); UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), ""); - rd.Scan(); - UNIT_ASSERT(rd.CgiParam.empty()); - } + rd.Scan(); + UNIT_ASSERT(rd.CgiParam.empty()); + } Y_UNIT_TEST(AppendQueryString) { const TString qs("gta=fake&haha=da"); TServerRequestData rd(qs.c_str()); - UNIT_ASSERT(rd.CgiParam.Has("gta", "fake")); - UNIT_ASSERT(rd.CgiParam.Has("haha", "da")); + UNIT_ASSERT(rd.CgiParam.Has("gta", "fake")); + UNIT_ASSERT(rd.CgiParam.Has("haha", "da")); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf()); @@ -128,11 +128,11 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) { UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs + '&' + appendix); UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); - rd.Scan(); + rd.Scan(); - UNIT_ASSERT(rd.CgiParam.Has("gta", "true")); - UNIT_ASSERT(rd.CgiParam.Has("gta", "new")); - } + UNIT_ASSERT(rd.CgiParam.Has("gta", "true")); + UNIT_ASSERT(rd.CgiParam.Has("gta", "new")); + } Y_UNIT_TEST(SetRemoteAddrSimple) { static const TString TEST = "abacaba.search.yandex.net"; diff --git a/library/cpp/http/misc/parsed_request.cpp b/library/cpp/http/misc/parsed_request.cpp index 8568293e2c..e332a24e91 100644 --- a/library/cpp/http/misc/parsed_request.cpp +++ b/library/cpp/http/misc/parsed_request.cpp @@ -1,32 +1,32 @@ -#include "parsed_request.h" - +#include "parsed_request.h" + #include <util/string/strip.h> -#include <util/generic/yexception.h> +#include <util/generic/yexception.h> #include <util/string/cast.h> - + static inline TStringBuf StripLeft(const TStringBuf& s) noexcept { - const char* b = s.begin(); - const char* e = s.end(); - - StripRangeBegin(b, e); - - return TStringBuf(b, e); -} - -TParsedHttpRequest::TParsedHttpRequest(const TStringBuf& str) { - TStringBuf tmp; - + const char* b = s.begin(); + const char* e = s.end(); + + StripRangeBegin(b, e); + + return TStringBuf(b, e); +} + +TParsedHttpRequest::TParsedHttpRequest(const TStringBuf& str) { + TStringBuf tmp; + if (!StripLeft(str).TrySplit(' ', Method, tmp)) { - ythrow yexception() << "bad request(" << ToString(str).Quote() << ")"; - } - + ythrow yexception() << "bad request(" << ToString(str).Quote() << ")"; + } + if (!StripLeft(tmp).TrySplit(' ', Request, Proto)) { - ythrow yexception() << "bad request(" << ToString(str).Quote() << ")"; - } - - Proto = StripLeft(Proto); -} - -TParsedHttpLocation::TParsedHttpLocation(const TStringBuf& req) { - req.Split('?', Path, Cgi); -} + ythrow yexception() << "bad request(" << ToString(str).Quote() << ")"; + } + + Proto = StripLeft(Proto); +} + +TParsedHttpLocation::TParsedHttpLocation(const TStringBuf& req) { + req.Split('?', Path, Cgi); +} diff --git a/library/cpp/http/misc/parsed_request.h b/library/cpp/http/misc/parsed_request.h index 00ba7767e7..d4df705495 100644 --- a/library/cpp/http/misc/parsed_request.h +++ b/library/cpp/http/misc/parsed_request.h @@ -1,26 +1,26 @@ #pragma once - -#include <util/generic/strbuf.h> - -struct TParsedHttpRequest { - TParsedHttpRequest(const TStringBuf& str); - - TStringBuf Method; - TStringBuf Request; - TStringBuf Proto; -}; - -struct TParsedHttpLocation { - TParsedHttpLocation(const TStringBuf& req); - - TStringBuf Path; - TStringBuf Cgi; -}; - -struct TParsedHttpFull: public TParsedHttpRequest, public TParsedHttpLocation { - inline TParsedHttpFull(const TStringBuf& line) - : TParsedHttpRequest(line) - , TParsedHttpLocation(Request) - { - } -}; + +#include <util/generic/strbuf.h> + +struct TParsedHttpRequest { + TParsedHttpRequest(const TStringBuf& str); + + TStringBuf Method; + TStringBuf Request; + TStringBuf Proto; +}; + +struct TParsedHttpLocation { + TParsedHttpLocation(const TStringBuf& req); + + TStringBuf Path; + TStringBuf Cgi; +}; + +struct TParsedHttpFull: public TParsedHttpRequest, public TParsedHttpLocation { + inline TParsedHttpFull(const TStringBuf& line) + : TParsedHttpRequest(line) + , TParsedHttpLocation(Request) + { + } +}; diff --git a/library/cpp/http/misc/parsed_request_ut.cpp b/library/cpp/http/misc/parsed_request_ut.cpp index d578f69f24..da6d95c6ab 100644 --- a/library/cpp/http/misc/parsed_request_ut.cpp +++ b/library/cpp/http/misc/parsed_request_ut.cpp @@ -1,28 +1,28 @@ -#include "parsed_request.h" - +#include "parsed_request.h" + #include <library/cpp/testing/unittest/registar.h> - + Y_UNIT_TEST_SUITE(THttpParse) { Y_UNIT_TEST(TestParse) { - TParsedHttpFull h("GET /yandsearch?text=nokia HTTP/1.1"); - - UNIT_ASSERT_EQUAL(h.Method, "GET"); - UNIT_ASSERT_EQUAL(h.Request, "/yandsearch?text=nokia"); - UNIT_ASSERT_EQUAL(h.Proto, "HTTP/1.1"); - - UNIT_ASSERT_EQUAL(h.Path, "/yandsearch"); - UNIT_ASSERT_EQUAL(h.Cgi, "text=nokia"); - } - + TParsedHttpFull h("GET /yandsearch?text=nokia HTTP/1.1"); + + UNIT_ASSERT_EQUAL(h.Method, "GET"); + UNIT_ASSERT_EQUAL(h.Request, "/yandsearch?text=nokia"); + UNIT_ASSERT_EQUAL(h.Proto, "HTTP/1.1"); + + UNIT_ASSERT_EQUAL(h.Path, "/yandsearch"); + UNIT_ASSERT_EQUAL(h.Cgi, "text=nokia"); + } + Y_UNIT_TEST(TestError) { - bool wasError = false; - - try { - TParsedHttpFull("GET /yandsearch?text=nokiaHTTP/1.1"); - } catch (...) { - wasError = true; - } - - UNIT_ASSERT(wasError); - } -} + bool wasError = false; + + try { + TParsedHttpFull("GET /yandsearch?text=nokiaHTTP/1.1"); + } catch (...) { + wasError = true; + } + + UNIT_ASSERT(wasError); + } +} diff --git a/library/cpp/http/misc/ut/ya.make b/library/cpp/http/misc/ut/ya.make index 49ca2b9aaf..f4bdd35662 100644 --- a/library/cpp/http/misc/ut/ya.make +++ b/library/cpp/http/misc/ut/ya.make @@ -1,11 +1,11 @@ UNITTEST_FOR(library/cpp/http/misc) - + OWNER(g:util) - -SRCS( - httpdate_ut.cpp - httpreqdata_ut.cpp - parsed_request_ut.cpp -) - -END() + +SRCS( + httpdate_ut.cpp + httpreqdata_ut.cpp + parsed_request_ut.cpp +) + +END() diff --git a/library/cpp/http/misc/ya.make b/library/cpp/http/misc/ya.make index 7a0f2a6e9f..fceb3cf79c 100644 --- a/library/cpp/http/misc/ya.make +++ b/library/cpp/http/misc/ya.make @@ -1,24 +1,24 @@ -LIBRARY() - +LIBRARY() + OWNER( g:util mvel ) - + GENERATE_ENUM_SERIALIZATION(httpcodes.h) -SRCS( - httpcodes.cpp - httpdate.cpp - httpreqdata.cpp - parsed_request.cpp -) - +SRCS( + httpcodes.cpp + httpdate.cpp + httpreqdata.cpp + parsed_request.cpp +) + PEERDIR( library/cpp/cgiparam library/cpp/digest/lower_case ) -END() +END() RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/http/server/conn.cpp b/library/cpp/http/server/conn.cpp index dd0860a315..38a76c4c30 100644 --- a/library/cpp/http/server/conn.cpp +++ b/library/cpp/http/server/conn.cpp @@ -1,31 +1,31 @@ -#include "conn.h" - -#include <util/network/socket.h> +#include "conn.h" + +#include <util/network/socket.h> #include <util/stream/buffered.h> - -class THttpServerConn::TImpl { -public: + +class THttpServerConn::TImpl { +public: inline TImpl(const TSocket& s, size_t outputBufferSize) - : S_(s) - , SI_(S_) - , SO_(S_) + : S_(s) + , SI_(S_) + , SO_(S_) , BO_(&SO_, outputBufferSize) - , HI_(&SI_) - , HO_(&BO_, &HI_) - { - } - + , HI_(&SI_) + , HO_(&BO_, &HI_) + { + } + inline ~TImpl() { - } - + } + inline THttpInput* Input() noexcept { - return &HI_; - } - + return &HI_; + } + inline THttpOutput* Output() noexcept { - return &HO_; - } - + return &HO_; + } + inline void Reset() { if (S_ != INVALID_SOCKET) { // send RST packet to client @@ -34,35 +34,35 @@ public: } } -private: - TSocket S_; - TSocketInput SI_; - TSocketOutput SO_; - TBufferedOutput BO_; - THttpInput HI_; - THttpOutput HO_; -}; - -THttpServerConn::THttpServerConn(const TSocket& s) +private: + TSocket S_; + TSocketInput SI_; + TSocketOutput SO_; + TBufferedOutput BO_; + THttpInput HI_; + THttpOutput HO_; +}; + +THttpServerConn::THttpServerConn(const TSocket& s) : THttpServerConn(s, s.MaximumTransferUnit()) -{ -} - +{ +} + THttpServerConn::THttpServerConn(const TSocket& s, size_t outputBufferSize) : Impl_(new TImpl(s, outputBufferSize)) { } THttpServerConn::~THttpServerConn() { -} - +} + THttpInput* THttpServerConn::Input() noexcept { - return Impl_->Input(); -} - + return Impl_->Input(); +} + THttpOutput* THttpServerConn::Output() noexcept { - return Impl_->Output(); -} + return Impl_->Output(); +} void THttpServerConn::Reset() { return Impl_->Reset(); diff --git a/library/cpp/http/server/conn.h b/library/cpp/http/server/conn.h index 93c2358c23..3aa5329af4 100644 --- a/library/cpp/http/server/conn.h +++ b/library/cpp/http/server/conn.h @@ -1,37 +1,37 @@ -#pragma once - +#pragma once + #include <library/cpp/http/io/stream.h> -#include <util/generic/ptr.h> - -class TSocket; - -/// Потоки ввода/вывода для получения запросов и отправки ответов HTTP-сервера. -class THttpServerConn { -public: - explicit THttpServerConn(const TSocket& s); - THttpServerConn(const TSocket& s, size_t outputBufferSize); +#include <util/generic/ptr.h> + +class TSocket; + +/// Потоки ввода/вывода для получения запросов и отправки ответов HTTP-сервера. +class THttpServerConn { +public: + explicit THttpServerConn(const TSocket& s); + THttpServerConn(const TSocket& s, size_t outputBufferSize); ~THttpServerConn(); - + THttpInput* Input() noexcept; THttpOutput* Output() noexcept; - + inline const THttpInput* Input() const noexcept { - return const_cast<THttpServerConn*>(this)->Input(); - } - + return const_cast<THttpServerConn*>(this)->Input(); + } + inline const THttpOutput* Output() const noexcept { - return const_cast<THttpServerConn*>(this)->Output(); - } - - /// Проверяет, можно ли установить режим, при котором соединение с сервером - /// не завершается после окончания транзакции. + return const_cast<THttpServerConn*>(this)->Output(); + } + + /// Проверяет, можно ли установить режим, при котором соединение с сервером + /// не завершается после окончания транзакции. inline bool CanBeKeepAlive() const noexcept { - return Output()->CanBeKeepAlive(); - } - + return Output()->CanBeKeepAlive(); + } + void Reset(); -private: - class TImpl; - THolder<TImpl> Impl_; -}; +private: + class TImpl; + THolder<TImpl> Impl_; +}; diff --git a/library/cpp/http/server/http.cpp b/library/cpp/http/server/http.cpp index 581fc77399..128583bdd7 100644 --- a/library/cpp/http/server/http.cpp +++ b/library/cpp/http/server/http.cpp @@ -1,12 +1,12 @@ #include "http.h" #include "http_ex.h" - + #include <library/cpp/threading/equeue/equeue.h> #include <util/generic/buffer.h> #include <util/generic/cast.h> -#include <util/generic/intrlist.h> -#include <util/generic/yexception.h> +#include <util/generic/intrlist.h> +#include <util/generic/yexception.h> #include <util/network/address.h> #include <util/network/socket.h> #include <util/network/poller.h> @@ -18,7 +18,7 @@ #include <util/system/pipe.h> #include <util/system/thread.h> #include <util/thread/factory.h> - + #include <cerrno> #include <cstring> #include <ctime> @@ -28,39 +28,39 @@ using namespace NAddr; -namespace { - class IPollAble { - public: +namespace { + class IPollAble { + public: inline IPollAble() noexcept { - } - - virtual ~IPollAble() { - } - + } + + virtual ~IPollAble() { + } + virtual void OnPollEvent(TInstant now) = 0; - }; - - struct TShouldStop { - }; + }; - struct TWakeupPollAble: public IPollAble { + struct TShouldStop { + }; + + struct TWakeupPollAble: public IPollAble { void OnPollEvent(TInstant) override { - throw TShouldStop(); - } - }; -} - -class TClientConnection: public IPollAble, public TIntrusiveListItem<TClientConnection> { + throw TShouldStop(); + } + }; +} + +class TClientConnection: public IPollAble, public TIntrusiveListItem<TClientConnection> { public: TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef); ~TClientConnection() override; - + void OnPollEvent(TInstant now) override; - + inline void Activate(TInstant now) noexcept; inline void DeActivate(); inline void Reject(); - + public: TSocket Socket_; NAddr::IRemoteAddrRef ListenerSockAddrRef_; @@ -69,28 +69,28 @@ public: TInstant LastUsed; TInstant AcceptMoment; size_t ReceivedRequests = 0; -}; - -class THttpServer::TImpl { +}; + +class THttpServer::TImpl { public: class TConnections { - public: + public: inline TConnections(TSocketPoller* poller, const THttpServerOptions& options) : Poller_(poller) , Options(options) { } - + inline ~TConnections() { } - + inline void Add(TClientConnection* c) noexcept { TGuard<TMutex> g(Mutex_); - + Conns_.PushBack(c); Poller_->WaitRead(c->Socket_, (void*)static_cast<const IPollAble*>(c)); } - + inline void Erase(TClientConnection* c, TInstant now) noexcept { TGuard<TMutex> g(Mutex_); EraseUnsafe(c); @@ -98,18 +98,18 @@ public: TryRemovingUnsafe(now - Options.ExpirationTimeout); } } - + inline void Clear() noexcept { TGuard<TMutex> g(Mutex_); - + Conns_.Clear(); } - + inline bool RemoveOld(TInstant border) noexcept { TGuard<TMutex> g(Mutex_); return TryRemovingUnsafe(border); } - + bool TryRemovingUnsafe(TInstant border) noexcept { if (Conns_.Empty()) { return false; @@ -122,7 +122,7 @@ public: delete c; return true; } - + void EraseUnsafe(TClientConnection* c) noexcept { Poller_->Unwait(c->Socket_); c->Unlink(); @@ -134,7 +134,7 @@ public: TSocketPoller* Poller_ = nullptr; const THttpServerOptions& Options; }; - + static void* ListenSocketFunction(void* param) { try { ((TImpl*)param)->ListenSocket(); @@ -144,10 +144,10 @@ public: return nullptr; } - + TAutoPtr<TClientRequest> CreateRequest(TAutoPtr<TClientConnection> c) { THolder<TClientRequest> obj(Cb_->CreateClient()); - + obj->Conn_.Reset(c.Release()); return obj; @@ -161,13 +161,13 @@ public: (new TClientConnection(s, this, listenerSockAddrRef))->Reject(); return; } - } - + } + auto connection = new TClientConnection(s, this, listenerSockAddrRef); connection->LastUsed = now; connection->DeActivate(); } - + void SaveErrorCode() { ErrorCode = WSAGetLastError(); } @@ -175,11 +175,11 @@ public: int GetErrorCode() const { return ErrorCode; } - + const char* GetError() const { return LastSystemErrorText(ErrorCode); } - + bool Start() { Poller.Reset(new TSocketPoller()); Connections.Reset(new TConnections(Poller.Get(), Options_)); @@ -202,14 +202,14 @@ public: } catch (const yexception&) { SaveErrorCode(); return false; - } - + } + // Wait until the thread has completely started and return the success indicator ListenStartEvent.Wait(); - + return ListenerRunningOK; } - + void Wait() { Cb_->OnWait(); TGuard<TMutex> g(StopMutex); @@ -227,46 +227,46 @@ public: ListenThread->Join(); ListenThread.Reset(nullptr); } - + while (ConnectionCount) { usleep(10000); Connections->Clear(); - } - + } + Connections.Destroy(); Poller.Destroy(); } - + void Shutdown() { ListenWakeupWriteFd.Write("", 1); // ignore result } - + void AddRequest(TAutoPtr<TClientRequest> req, bool fail) { struct TFailRequest: public THttpClientRequestEx { - inline TFailRequest(TAutoPtr<TClientRequest> parent) { - Conn_.Reset(parent->Conn_.Release()); - HttpConn_.Reset(parent->HttpConn_.Release()); - } - + inline TFailRequest(TAutoPtr<TClientRequest> parent) { + Conn_.Reset(parent->Conn_.Release()); + HttpConn_.Reset(parent->HttpConn_.Release()); + } + bool Reply(void*) override { if (!ProcessHeaders()) { return true; } - ProcessFailRequest(0); - return true; - } + ProcessFailRequest(0); + return true; + } }; - + if (!fail && Requests->Add(req.Get())) { Y_UNUSED(req.Release()); } else { req = new TFailRequest(req); - + if (FailRequests->Add(req.Get())) { Y_UNUSED(req.Release()); - } else { + } else { Cb_->OnFailRequest(-1); } } @@ -288,44 +288,44 @@ public: return *FailRequests; } - class TListenSocket: public IPollAble, public TIntrusiveListItem<TListenSocket> { - public: - inline TListenSocket(const TSocket& s, TImpl* parent) - : S_(s) - , Server_(parent) + class TListenSocket: public IPollAble, public TIntrusiveListItem<TListenSocket> { + public: + inline TListenSocket(const TSocket& s, TImpl* parent) + : S_(s) + , Server_(parent) , SockAddrRef_(GetSockAddr(S_)) - { - } - + { + } + ~TListenSocket() override { - } - + } + void OnPollEvent(TInstant) override { SOCKET s = ::accept(S_, nullptr, nullptr); - - if (s == INVALID_SOCKET) { - ythrow yexception() << "accept: " << LastSystemErrorText(); + + if (s == INVALID_SOCKET) { + ythrow yexception() << "accept: " << LastSystemErrorText(); } Server_->AddRequestFromSocket(s, TInstant::Now(), SockAddrRef_); - } + } SOCKET GetSocket() const noexcept { - return S_; - } - - private: - TSocket S_; + return S_; + } + + private: + TSocket S_; TImpl* Server_ = nullptr; NAddr::IRemoteAddrRef SockAddrRef_; }; - + void ListenSocket() { TThread::SetCurrentThreadName(Options_.ListenThreadName.c_str()); ErrorCode = 0; TIntrusiveListWithAutoDelete<TListenSocket, TDelete> Reqs; - + std::function<void(TSocket)> callback = [&](TSocket socket) { THolder<TListenSocket> ls(new TListenSocket(socket, this)); Poller->WaitRead(socket, static_cast<IPollAble*>(ls.Get())); @@ -335,7 +335,7 @@ public: if (!addressesBound) { SaveErrorCode(); ListenStartEvent.Signal(); - + return; } @@ -347,18 +347,18 @@ public: TVector<void*> events; events.resize(1); - + TInstant now = TInstant::Now(); - for (;;) { + for (;;) { try { const TInstant deadline = Options_.PollTimeout == TDuration::Zero() ? TInstant::Max() : now + Options_.PollTimeout; const size_t ret = Poller->WaitD(events.data(), events.size(), deadline); - + now = TInstant::Now(); for (size_t i = 0; i < ret; ++i) { ((IPollAble*)events[i])->OnPollEvent(now); } - + if (ret == 0 && Options_.ExpirationTimeout > TDuration::Zero()) { Connections->RemoveOld(now - Options_.ExpirationTimeout); } @@ -370,26 +370,26 @@ public: if (!Options_.MaxConnections && Options_.ExpirationTimeout == TDuration::Zero()) { if (ret >= events.size()) { events.resize(ret * 2); - } - } - } catch (const TShouldStop&) { - break; + } + } + } catch (const TShouldStop&) { + break; } catch (...) { Cb_->OnException(); - } - } + } + } while (!Reqs.Empty()) { THolder<TListenSocket> ls(Reqs.PopFront()); - + Poller->Unwait(ls->GetSocket()); - } - + } + Requests->Stop(); FailRequests->Stop(); Cb_->OnListenStop(); } - + void RestartRequestThreads(ui32 nTh, ui32 maxQS) { Requests->Stop(); Options_.nThreads = nTh; @@ -408,24 +408,24 @@ public: TImpl(THttpServer* parent, ICallBack* cb, const TOptions& options, IThreadFactory* factory) : TImpl( - parent, - cb, + parent, + cb, MakeThreadPool<TSimpleThreadPool>(factory, options.UseElasticQueues, cb, options.RequestsThreadName), MakeThreadPool<TThreadPool>(factory, options.UseElasticQueues, nullptr, options.FailRequestsThreadName), - options) { + options) { } ~TImpl() { try { Stop(); } catch (...) { - } + } } - + inline const TOptions& Options() const noexcept { return Options_; } - + inline void DecreaseConnections() noexcept { AtomicDecrement(ConnectionCount); } @@ -439,7 +439,7 @@ public: } inline bool MaxRequestsReached() const { - return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections); + return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections); } THolder<TThread> ListenThread; @@ -480,57 +480,57 @@ private: return pool; } -}; +}; THttpServer::THttpServer(ICallBack* cb, const TOptions& options, IThreadFactory* pool) : Impl_(new TImpl(this, cb, options, pool)) -{ -} - +{ +} + THttpServer::THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options) : Impl_(new TImpl(this, cb, mainWorkers, failWorkers, options)) { } -THttpServer::~THttpServer() { -} - +THttpServer::~THttpServer() { +} + i64 THttpServer::GetClientCount() const { return Impl_->GetClientCount(); } -bool THttpServer::Start() { - return Impl_->Start(); -} - -void THttpServer::Stop() { - Impl_->Stop(); -} - -void THttpServer::Shutdown() { - Impl_->Shutdown(); -} - -void THttpServer::Wait() { - Impl_->Wait(); -} - -int THttpServer::GetErrorCode() { - return Impl_->GetErrorCode(); -} - -const char* THttpServer::GetError() { - return Impl_->GetError(); -} - -void THttpServer::RestartRequestThreads(ui32 n, ui32 queue) { - Impl_->RestartRequestThreads(n, queue); -} - +bool THttpServer::Start() { + return Impl_->Start(); +} + +void THttpServer::Stop() { + Impl_->Stop(); +} + +void THttpServer::Shutdown() { + Impl_->Shutdown(); +} + +void THttpServer::Wait() { + Impl_->Wait(); +} + +int THttpServer::GetErrorCode() { + return Impl_->GetErrorCode(); +} + +const char* THttpServer::GetError() { + return Impl_->GetError(); +} + +void THttpServer::RestartRequestThreads(ui32 n, ui32 queue) { + Impl_->RestartRequestThreads(n, queue); +} + const THttpServer::TOptions& THttpServer::Options() const noexcept { - return Impl_->Options(); -} - + return Impl_->Options(); +} + size_t THttpServer::GetRequestQueueSize() const { return Impl_->GetRequestQueueSize(); } @@ -552,45 +552,45 @@ bool THttpServer::MaxRequestsReached() const { } TClientConnection::TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef) - : Socket_(s) + : Socket_(s) , ListenerSockAddrRef_(listenerSockAddrRef) - , HttpServ_(serv) -{ - SetNoDelay(Socket_, true); - + , HttpServ_(serv) +{ + SetNoDelay(Socket_, true); + const TDuration& clientTimeout = HttpServ_->Options().ClientTimeout; if (clientTimeout != TDuration::Zero()) { SetSocketTimeout(Socket_, (long)clientTimeout.Seconds(), clientTimeout.MilliSecondsOfSecond()); } - HttpServ_->IncreaseConnections(); -} - + HttpServ_->IncreaseConnections(); +} + TClientConnection::~TClientConnection() { - HttpServ_->DecreaseConnections(); -} - + HttpServ_->DecreaseConnections(); +} + void TClientConnection::OnPollEvent(TInstant now) { THolder<TClientConnection> this_(this); Activate(now); - - { - char tmp[1]; - - if (::recv(Socket_, tmp, 1, MSG_PEEK) < 1) { - /* - * We can received a FIN so our socket was moved to - * TCP_CLOSE_WAIT state. Check it before adding work - * for this socket. - */ - - return; - } - } - + + { + char tmp[1]; + + if (::recv(Socket_, tmp, 1, MSG_PEEK) < 1) { + /* + * We can received a FIN so our socket was moved to + * TCP_CLOSE_WAIT state. Check it before adding work + * for this socket. + */ + + return; + } + } + THolder<TClientRequest> obj(HttpServ_->CreateRequest(this_)); AcceptMoment = now; - + HttpServ_->AddRequest(obj, Reject_); } @@ -600,35 +600,35 @@ void TClientConnection::Activate(TInstant now) noexcept { ++ReceivedRequests; } -void TClientConnection::DeActivate() { +void TClientConnection::DeActivate() { HttpServ_->Connections->Add(this); -} - +} + void TClientConnection::Reject() { Reject_ = true; HttpServ_->Connections->Add(this); } -TClientRequest::TClientRequest() { -} - -TClientRequest::~TClientRequest() { -} - -bool TClientRequest::Reply(void* /*ThreadSpecificResource*/) { +TClientRequest::TClientRequest() { +} + +TClientRequest::~TClientRequest() { +} + +bool TClientRequest::Reply(void* /*ThreadSpecificResource*/) { if (strnicmp(RequestString.data(), "GET ", 4)) { - Output() << "HTTP/1.0 501 Not Implemented\r\n\r\n"; - } else { - Output() << "HTTP/1.0 200 OK\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "Hello World!\r\n"; - } - - return true; -} - + Output() << "HTTP/1.0 501 Not Implemented\r\n\r\n"; + } else { + Output() << "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "Hello World!\r\n"; + } + + return true; +} + bool TClientRequest::IsLocal() const { return HasLocalAddress(Socket()); } @@ -639,29 +639,29 @@ bool TClientRequest::CheckLoopback() { try { isLocal = IsLocal(); } catch (const yexception& e) { - Output() << "HTTP/1.0 500 Oops\r\n\r\n" - << e.what() << "\r\n"; - return false; + Output() << "HTTP/1.0 500 Oops\r\n\r\n" + << e.what() << "\r\n"; + return false; } if (!isLocal) { - Output() << "HTTP/1.0 403 Permission denied\r\n" - "Content-Type: text/html; charset=windows-1251\r\n" - "Connection: close\r\n" - "\r\n" - "<html><head><title>Permission denied</title></head>" - "<body><h1>Permission denied</h1>" - "<p>This request must be sent from the localhost.</p>" - "</body></html>\r\n"; - - return false; - } - - return true; -} - + Output() << "HTTP/1.0 403 Permission denied\r\n" + "Content-Type: text/html; charset=windows-1251\r\n" + "Connection: close\r\n" + "\r\n" + "<html><head><title>Permission denied</title></head>" + "<body><h1>Permission denied</h1>" + "<p>This request must be sent from the localhost.</p>" + "</body></html>\r\n"; + + return false; + } + + return true; +} + void TClientRequest::ReleaseConnection() { - if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) { + if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) { Output().Finish(); Conn_->DeActivate(); Y_UNUSED(Conn_.Release()); @@ -676,101 +676,101 @@ void TClientRequest::ResetConnection() { } } -void TClientRequest::Process(void* ThreadSpecificResource) { +void TClientRequest::Process(void* ThreadSpecificResource) { THolder<TClientRequest> this_(this); - + auto* serverImpl = Conn_->HttpServ_; - try { - if (!HttpConn_) { + try { + if (!HttpConn_) { const size_t outputBufferSize = HttpServ()->Options().OutputBufferSize; if (outputBufferSize) { HttpConn_.Reset(new THttpServerConn(Socket(), outputBufferSize)); } else { HttpConn_.Reset(new THttpServerConn(Socket())); } - + auto maxRequestsPerConnection = HttpServ()->Options().MaxRequestsPerConnection; HttpConn_->Output()->EnableKeepAlive(HttpServ()->Options().KeepAliveEnabled && (!maxRequestsPerConnection || Conn_->ReceivedRequests < maxRequestsPerConnection)); - HttpConn_->Output()->EnableCompression(HttpServ()->Options().CompressionEnabled); - } - + HttpConn_->Output()->EnableCompression(HttpServ()->Options().CompressionEnabled); + } + if (ParsedHeaders.empty()) { RequestString = Input().FirstLine(); - - const THttpHeaders& h = Input().Headers(); + + const THttpHeaders& h = Input().Headers(); ParsedHeaders.reserve(h.Count()); - for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) { + for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) { ParsedHeaders.emplace_back(it->Name(), it->Value()); - } - } - - if (Reply(ThreadSpecificResource)) { + } + } + + if (Reply(ThreadSpecificResource)) { ReleaseConnection(); - - /* - * *this will be destroyed... - */ - - return; - } - } catch (...) { + + /* + * *this will be destroyed... + */ + + return; + } + } catch (...) { serverImpl->Cb_->OnException(); - - throw; - } - + + throw; + } + Y_UNUSED(this_.Release()); -} - -void TClientRequest::ProcessFailRequest(int failstate) { +} + +void TClientRequest::ProcessFailRequest(int failstate) { Output() << "HTTP/1.1 503 Service Unavailable\r\n" "Content-Type: text/plain\r\n" "Content-Length: 21\r\n" "\r\n" "Service Unavailable\r\n"; - + TString url; - + if (!strnicmp(RequestString.data(), "GET ", 4)) { - // Trying to extract url... + // Trying to extract url... const char* str = RequestString.data(); - - // Skipping spaces before url... - size_t start = 3; + + // Skipping spaces before url... + size_t start = 3; while (str[start] == ' ') { - ++start; - } - - if (str[start]) { - // Traversing url... - size_t idx = start; - - while (str[idx] != ' ' && str[idx]) { - ++idx; - } - + ++start; + } + + if (str[start]) { + // Traversing url... + size_t idx = start; + + while (str[idx] != ' ' && str[idx]) { + ++idx; + } + url = RequestString.substr(start, idx - start); - } - } - - const THttpServer::ICallBack::TFailLogData d = { - failstate, - url, - }; - - // Handling failure... - Conn_->HttpServ_->Cb_->OnFailRequestEx(d); - Output().Flush(); -} - + } + } + + const THttpServer::ICallBack::TFailLogData d = { + failstate, + url, + }; + + // Handling failure... + Conn_->HttpServ_->Cb_->OnFailRequestEx(d); + Output().Flush(); +} + THttpServer* TClientRequest::HttpServ() const noexcept { - return Conn_->HttpServ_->Parent_; -} - + return Conn_->HttpServ_->Parent_; +} + const TSocket& TClientRequest::Socket() const noexcept { - return Conn_->Socket_; -} + return Conn_->Socket_; +} NAddr::IRemoteAddrRef TClientRequest::GetListenerSockAddrRef() const noexcept { return Conn_->ListenerSockAddrRef_; @@ -791,8 +791,8 @@ TRequestReplier::~TRequestReplier() { bool TRequestReplier::Reply(void* threadSpecificResource) { const TReplyParams params = { - threadSpecificResource, Input(), Output()}; - + threadSpecificResource, Input(), Output()}; + return DoReply(params); } @@ -833,7 +833,7 @@ bool TryToBindAddresses(const THttpServerOptions& options, const std::function<v return false; } - if (callbackOnBoundAddress != nullptr) { + if (callbackOnBoundAddress != nullptr) { (*callbackOnBoundAddress)(socket); } } diff --git a/library/cpp/http/server/http.h b/library/cpp/http/server/http.h index 1b72215706..b292d38f27 100644 --- a/library/cpp/http/server/http.h +++ b/library/cpp/http/server/http.h @@ -1,92 +1,92 @@ #pragma once -#include "conn.h" -#include "options.h" - +#include "conn.h" +#include "options.h" + #include <util/thread/pool.h> #include <library/cpp/http/io/stream.h> -#include <util/memory/blob.h> +#include <util/memory/blob.h> #include <util/generic/ptr.h> #include <util/generic/vector.h> #include <util/system/atomic.h> - + class IThreadFactory; -class TClientRequest; -class TClientConnection; +class TClientRequest; +class TClientConnection; -class THttpServer { +class THttpServer { friend class TClientRequest; friend class TClientConnection; - + public: class ICallBack { - public: + public: struct TFailLogData { int failstate; TString url; }; - + virtual ~ICallBack() { } - + virtual void OnFailRequest(int /*failstate*/) { } - + virtual void OnFailRequestEx(const TFailLogData& d) { OnFailRequest(d.failstate); } - + virtual void OnException() { } - + virtual void OnMaxConn() { } - + virtual TClientRequest* CreateClient() = 0; - + virtual void OnListenStart() { } - + virtual void OnListenStop() { } - + virtual void OnWait() { } - - virtual void* CreateThreadSpecificResource() { + + virtual void* CreateThreadSpecificResource() { return nullptr; } - + virtual void DestroyThreadSpecificResource(void*) { } }; - + typedef THttpServerOptions TOptions; typedef TSimpleSharedPtr<IThreadPool> TMtpQueueRef; - + THttpServer(ICallBack* cb, const TOptions& options = TOptions(), IThreadFactory* pool = nullptr); THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options = TOptions()); virtual ~THttpServer(); - + bool Start(); - + // shutdown a.s.a.p. void Stop(); - + // graceful shutdown with serving all already open connections void Shutdown(); - + void Wait(); int GetErrorCode(); const char* GetError(); void RestartRequestThreads(ui32 nTh, ui32 maxQS); const TOptions& Options() const noexcept; i64 GetClientCount() const; - + class TImpl; size_t GetRequestQueueSize() const; size_t GetFailQueueSize() const; - + const IThreadPool& GetRequestQueue() const; const IThreadPool& GetFailQueue() const; @@ -102,32 +102,32 @@ private: /** * @deprecated Use TRequestReplier instead */ -class TClientRequest: public IObjectInQueue { +class TClientRequest: public IObjectInQueue { friend class THttpServer::TImpl; - + public: TClientRequest(); ~TClientRequest() override; - + inline THttpInput& Input() noexcept { return *HttpConn_->Input(); } - + inline THttpOutput& Output() noexcept { return *HttpConn_->Output(); } - + THttpServer* HttpServ() const noexcept; const TSocket& Socket() const noexcept; NAddr::IRemoteAddrRef GetListenerSockAddrRef() const noexcept; TInstant AcceptMoment() const noexcept; - + bool IsLocal() const; bool CheckLoopback(); void ProcessFailRequest(int failstate); - + void ReleaseConnection(); - + void ResetConnection(); private: @@ -138,17 +138,17 @@ private: */ virtual bool Reply(void* ThreadSpecificResource); void Process(void* ThreadSpecificResource) override; - + public: TVector<std::pair<TString, TString>> ParsedHeaders; TString RequestString; - + private: THolder<TClientConnection> Conn_; THolder<THttpServerConn> HttpConn_; -}; - -class TRequestReplier: public TClientRequest { +}; + +class TRequestReplier: public TClientRequest { public: TRequestReplier(); ~TRequestReplier() override; diff --git a/library/cpp/http/server/http_ex.cpp b/library/cpp/http/server/http_ex.cpp index 2fa2ccfead..e07db22bfc 100644 --- a/library/cpp/http/server/http_ex.cpp +++ b/library/cpp/http/server/http_ex.cpp @@ -1,32 +1,32 @@ -#include "http_ex.h" - -#include <util/generic/buffer.h> -#include <util/generic/cast.h> +#include "http_ex.h" + +#include <util/generic/buffer.h> +#include <util/generic/cast.h> #include <util/stream/null.h> - + bool THttpClientRequestExtension::Parse(char* req, TBaseServerRequestData& rd) { rd.SetSocket(Socket()); - + if (!rd.Parse(req)) { - Output() << "HTTP/1.1 403 Forbidden\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 39\r\n" - "\r\n" - "The server cannot be used as a proxy.\r\n"; - - return false; - } - - return true; -} - + Output() << "HTTP/1.1 403 Forbidden\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 39\r\n" + "\r\n" + "The server cannot be used as a proxy.\r\n"; + + return false; + } + + return true; +} + bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData) { - for (const auto& header : ParsedHeaders) { + for (const auto& header : ParsedHeaders) { rd.AddHeader(header.first, header.second); - } - + } + char* s = RequestString.begin(); - + enum EMethod { NotImplemented, Get, @@ -39,7 +39,7 @@ bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBl enum EMethod foundMethod; char* urlStart; - if (strnicmp(s, "GET ", 4) == 0) { + if (strnicmp(s, "GET ", 4) == 0) { foundMethod = Get; urlStart = s + 4; } else if (strnicmp(s, "POST ", 5) == 0) { @@ -59,49 +59,49 @@ bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBl } switch (foundMethod) { - case Get: - case Delete: - if (!Parse(urlStart, rd)) { - return false; - } - break; - - case Post: - case Put: + case Get: + case Delete: + if (!Parse(urlStart, rd)) { + return false; + } + break; + + case Post: + case Put: case Patch: - try { - ui64 contentLength = 0; - if (Input().HasExpect100Continue()) { - Output().SendContinue(); - } - - if (!Input().ContentEncoded() && Input().GetContentLength(contentLength)) { + try { + ui64 contentLength = 0; + if (Input().HasExpect100Continue()) { + Output().SendContinue(); + } + + if (!Input().ContentEncoded() && Input().GetContentLength(contentLength)) { if (contentLength > HttpServ()->Options().MaxInputContentLength) { Output() << "HTTP/1.1 413 Payload Too Large\r\nContent-Length:0\r\n\r\n"; Output().Finish(); return false; } - TBuffer buf(SafeIntegerCast<size_t>(contentLength)); - buf.Resize(Input().Load(buf.Data(), (size_t)contentLength)); - postData = TBlob::FromBuffer(buf); - } else { - postData = TBlob::FromStream(Input()); - } - } catch (...) { - Output() << "HTTP/1.1 400 Bad request\r\n\r\n"; - return false; + TBuffer buf(SafeIntegerCast<size_t>(contentLength)); + buf.Resize(Input().Load(buf.Data(), (size_t)contentLength)); + postData = TBlob::FromBuffer(buf); + } else { + postData = TBlob::FromStream(Input()); + } + } catch (...) { + Output() << "HTTP/1.1 400 Bad request\r\n\r\n"; + return false; } - if (!Parse(urlStart, rd)) { - return false; - } - break; - - case NotImplemented: - Output() << "HTTP/1.1 501 Not Implemented\r\n\r\n"; - return false; - } - - return true; -} + if (!Parse(urlStart, rd)) { + return false; + } + break; + + case NotImplemented: + Output() << "HTTP/1.1 501 Not Implemented\r\n\r\n"; + return false; + } + + return true; +} diff --git a/library/cpp/http/server/http_ex.h b/library/cpp/http/server/http_ex.h index 39cfbbe66f..1ef43ea4fd 100644 --- a/library/cpp/http/server/http_ex.h +++ b/library/cpp/http/server/http_ex.h @@ -1,28 +1,28 @@ -#pragma once - -#include "http.h" - +#pragma once + +#include "http.h" + #include <library/cpp/http/misc/httpreqdata.h> - -class THttpClientRequestExtension: public TClientRequest { + +class THttpClientRequestExtension: public TClientRequest { public: bool Parse(char* req, TBaseServerRequestData& rd); bool ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData); }; - + template <class TRequestData> -class THttpClientRequestExtImpl: public THttpClientRequestExtension { -protected: +class THttpClientRequestExtImpl: public THttpClientRequestExtension { +protected: bool Parse(char* req) { return THttpClientRequestExtension::Parse(req, RD); } bool ProcessHeaders() { return THttpClientRequestExtension::ProcessHeaders(RD, Buf); } - + protected: TRequestData RD; - TBlob Buf; -}; + TBlob Buf; +}; using THttpClientRequestEx = THttpClientRequestExtImpl<TServerRequestData>; diff --git a/library/cpp/http/server/http_ut.cpp b/library/cpp/http/server/http_ut.cpp index ab24207eac..cc62bb988e 100644 --- a/library/cpp/http/server/http_ut.cpp +++ b/library/cpp/http/server/http_ut.cpp @@ -1,58 +1,58 @@ -#include "http.h" -#include "http_ex.h" - +#include "http.h" +#include "http_ex.h" + #include <library/cpp/testing/unittest/registar.h> #include <library/cpp/testing/unittest/tests_data.h> - + #include <util/generic/cast.h> #include <util/stream/output.h> #include <util/stream/zlib.h> #include <util/system/datetime.h> #include <util/system/sem.h> - + Y_UNIT_TEST_SUITE(THttpServerTest) { - class TEchoServer: public THttpServer::ICallBack { + class TEchoServer: public THttpServer::ICallBack { class TRequest: public THttpClientRequestEx { - public: - inline TRequest(TEchoServer* parent) - : Parent_(parent) - { - } - + public: + inline TRequest(TEchoServer* parent) + : Parent_(parent) + { + } + bool Reply(void* /*tsr*/) override { - if (!ProcessHeaders()) { + if (!ProcessHeaders()) { return true; - } - - Output() << "HTTP/1.1 200 Ok\r\n\r\n"; + } + + Output() << "HTTP/1.1 200 Ok\r\n\r\n"; if (Buf.Size()) { Output().Write(Buf.AsCharPtr(), Buf.Size()); - } else { - Output() << Parent_->Res_; - } - Output().Finish(); - - return true; - } - - private: + } else { + Output() << Parent_->Res_; + } + Output().Finish(); + + return true; + } + + private: TEchoServer* Parent_ = nullptr; - }; - - public: + }; + + public: inline TEchoServer(const TString& res) - : Res_(res) - { - } - + : Res_(res) + { + } + TClientRequest* CreateClient() override { - return new TRequest(this); - } - - private: + return new TRequest(this); + } + + private: TString Res_; - }; - + }; + class TSleepingServer: public THttpServer::ICallBack { class TReplier: public TRequestReplier { public: @@ -269,7 +269,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { TStringStream ss; ss << (KeepAliveConnection ? "keep-alive " : "") << Type; if (ContentEncoding.size()) { - ss << " with encoding=" << ContentEncoding; + ss << " with encoding=" << ContentEncoding; } return ss.Str(); } else { @@ -292,7 +292,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { class TFailingMtpQueue: public TSimpleThreadPool { private: bool FailOnAdd_ = false; - + public: void SetFailOnAdd(bool fail = true) { FailOnAdd_ = fail; @@ -313,47 +313,47 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { TString TestData(size_t size = 5 * 4096) { TString res; - + for (size_t i = 0; i < size; ++i) { - res += (char)i; - } + res += (char)i; + } return res; } - + Y_UNIT_TEST(TestEchoServer) { TString res = TestData(); TPortManager pm; const ui16 port = pm.GetPort(); const bool trueFalse[] = {true, false}; - - TEchoServer serverImpl(res); - THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true)); - + + TEchoServer serverImpl(res); + THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true)); + for (int i = 0; i < 2; ++i) { UNIT_ASSERT(server.Start()); - + TTestRequest r(port); r.Content = res; - - for (bool keepAlive : trueFalse) { + + for (bool keepAlive : trueFalse) { r.KeepAliveConnection = keepAlive; - + // THttpOutput use chunked stream, else use Content-Length - for (bool useHttpOutput : trueFalse) { + for (bool useHttpOutput : trueFalse) { r.UseHttpOutput = useHttpOutput; - - for (bool enableResponseEncoding : trueFalse) { + + for (bool enableResponseEncoding : trueFalse) { r.EnableResponseEncoding = enableResponseEncoding; - + const TString reqTypes[] = {"GET", "POST"}; for (const TString& reqType : reqTypes) { r.Type = reqType; - + const TString encoders[] = {"", "deflate"}; for (const TString& encoder : encoders) { r.ContentEncoding = encoder; - - for (bool expect100Continue : trueFalse) { + + for (bool expect100Continue : trueFalse) { r.Expect100Continue = expect100Continue; TString resp = r.Execute(); UNIT_ASSERT_C(resp == res, "diff echo response for request:\n" + r.GetDescription()); @@ -365,12 +365,12 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { } server.Stop(); - } - } + } + } Y_UNIT_TEST(TestReusePortEnabled) { if (!IsReusePortAvailable()) { - return; // skip test + return; // skip test } TString res = TestData(); TPortManager pm; @@ -383,7 +383,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { } for (ui32 testRun = 0; testRun < 3; testRun++) { - for (auto& server : servers) { + for (auto& server : servers) { // start servers one at a time and check at least one of them is replying UNIT_ASSERT(server->Start()); @@ -391,7 +391,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { UNIT_ASSERT_C(r.Execute() == res, "diff echo response for request:\n" + r.GetDescription()); } - for (auto& server : servers) { + for (auto& server : servers) { // ping servers and stop them one at a time // at the last iteration only one server is still working and then gets stopped as well @@ -471,7 +471,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { return true; } }; - + public: TClientRequest* CreateClient() override { return new TRequest(); @@ -684,7 +684,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { server.Stop(); }; -#if 0 +#if 0 Y_UNIT_TEST(TestSocketsLeak) { const bool trueFalse[] = {true, false}; TPortManager portManager; @@ -709,7 +709,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { server.BusyThread(); for (size_t i = 0; i < 3; ++i) { - auto func = [&server, port, keepAlive]() { + auto func = [&server, port, keepAlive]() { server.BusyThread(); THolder<TTestRequest> r = MakeHolder<TTestRequest>(port); r->KeepAliveConnection = keepAlive; @@ -722,7 +722,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { Sleep(TDuration::MilliSeconds(100)); server.BusyThread(); // we wait while connections are established by the // system and accepted by the server - server.Free(3); // we release all connections processing + server.Free(3); // we release all connections processing for (auto&& thread : threads) { thread->Join(); @@ -735,5 +735,5 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { UNIT_ASSERT_EQUAL_C(server.RepliesCount(), 1, "only one request should have been processed, got " + ToString(server.RepliesCount())); } } -#endif -} +#endif +} diff --git a/library/cpp/http/server/options.cpp b/library/cpp/http/server/options.cpp index 391ac68a11..05c954384a 100644 --- a/library/cpp/http/server/options.cpp +++ b/library/cpp/http/server/options.cpp @@ -1,12 +1,12 @@ -#include "options.h" - +#include "options.h" + #include <util/string/cast.h> -#include <util/digest/numeric.h> -#include <util/network/ip.h> -#include <util/network/socket.h> -#include <util/generic/hash_set.h> -#include <util/generic/yexception.h> - +#include <util/digest/numeric.h> +#include <util/network/ip.h> +#include <util/network/socket.h> +#include <util/generic/hash_set.h> +#include <util/generic/yexception.h> + using TAddr = THttpServerOptions::TAddr; static inline TString AddrToString(const TAddr& addr) { @@ -16,28 +16,28 @@ static inline TString AddrToString(const TAddr& addr) { static inline TNetworkAddress ToNetworkAddr(const TString& address, ui16 port) { if (address.empty() || address == TStringBuf("*")) { return TNetworkAddress(port); - } - + } + return TNetworkAddress(address, port); -} - -void THttpServerOptions::BindAddresses(TBindAddresses& ret) const { +} + +void THttpServerOptions::BindAddresses(TBindAddresses& ret) const { THashSet<TString> check; - + for (auto addr : BindSockaddr) { if (!addr.Port) { addr.Port = Port; - } - + } + const TString straddr = AddrToString(addr); if (check.find(straddr) == check.end()) { check.insert(straddr); ret.push_back(ToNetworkAddr(addr.Addr, addr.Port)); - } - } - - if (ret.empty()) { + } + } + + if (ret.empty()) { ret.push_back(Host ? TNetworkAddress(Host, Port) : TNetworkAddress(Port)); - } -} + } +} diff --git a/library/cpp/http/server/options.h b/library/cpp/http/server/options.h index 28ce8be0e1..38eda0e5e7 100644 --- a/library/cpp/http/server/options.h +++ b/library/cpp/http/server/options.h @@ -1,49 +1,49 @@ #pragma once - -#include <util/network/ip.h> -#include <util/network/init.h> + +#include <util/network/ip.h> +#include <util/network/init.h> #include <util/network/address.h> #include <util/generic/size_literals.h> #include <util/generic/string.h> -#include <util/generic/vector.h> +#include <util/generic/vector.h> #include <util/datetime/base.h> - -class THttpServerOptions { -public: + +class THttpServerOptions { +public: inline THttpServerOptions(ui16 port = 17000) noexcept : Port(port) - { - } - + { + } + using TBindAddresses = TVector<TNetworkAddress>; - void BindAddresses(TBindAddresses& ret) const; - + void BindAddresses(TBindAddresses& ret) const; + inline THttpServerOptions& AddBindAddress(const TString& address, ui16 port) { const TAddr addr = { - address, - port, - }; - + address, + port, + }; + BindSockaddr.push_back(addr); return *this; } inline THttpServerOptions& AddBindAddress(const TString& address) { return AddBindAddress(address, 0); - } - + } + inline THttpServerOptions& EnableKeepAlive(bool enable) noexcept { - KeepAliveEnabled = enable; - - return *this; - } - + KeepAliveEnabled = enable; + + return *this; + } + inline THttpServerOptions& EnableCompression(bool enable) noexcept { - CompressionEnabled = enable; - - return *this; - } - + CompressionEnabled = enable; + + return *this; + } + inline THttpServerOptions& EnableRejectExcessConnections(bool enable) noexcept { RejectExcessConnections = enable; @@ -63,11 +63,11 @@ public: } inline THttpServerOptions& SetThreads(ui32 threads) noexcept { - nThreads = threads; - - return *this; - } - + nThreads = threads; + + return *this; + } + /// Default interface name to bind the server. Used when none of BindAddress are provided. inline THttpServerOptions& SetHost(const TString& host) noexcept { Host = host; @@ -77,35 +77,35 @@ public: /// Default port to bind the server. Used when none of BindAddress are provided. inline THttpServerOptions& SetPort(ui16 port) noexcept { - Port = port; - - return *this; - } - + Port = port; + + return *this; + } + inline THttpServerOptions& SetMaxConnections(ui32 mc = 0) noexcept { - MaxConnections = mc; - - return *this; - } - + MaxConnections = mc; + + return *this; + } + inline THttpServerOptions& SetMaxQueueSize(ui32 mqs = 0) noexcept { - MaxQueueSize = mqs; - - return *this; - } + MaxQueueSize = mqs; + + return *this; + } inline THttpServerOptions& SetClientTimeout(const TDuration& timeout) noexcept { - ClientTimeout = timeout; + ClientTimeout = timeout; + + return *this; + } - return *this; - } - inline THttpServerOptions& SetListenBacklog(int val) noexcept { - ListenBacklog = val; - - return *this; - } - + ListenBacklog = val; + + return *this; + } + inline THttpServerOptions& SetOutputBufferSize(size_t val) noexcept { OutputBufferSize = val; @@ -149,19 +149,19 @@ public: bool KeepAliveEnabled = true; bool CompressionEnabled = false; bool RejectExcessConnections = false; - bool ReusePort = false; // set SO_REUSEPORT socket option + bool ReusePort = false; // set SO_REUSEPORT socket option bool ReuseAddress = true; // set SO_REUSEADDR socket option - TAddrs BindSockaddr; - ui16 Port = 17000; // The port on which to run the web server - TString Host; // DNS entry - const char* ServerName = "YWS/1.0"; // The Web server name to return in HTTP headers - ui32 nThreads = 0; // Thread count for requests processing - ui32 MaxQueueSize = 0; // Max allowed request count in queue + TAddrs BindSockaddr; + ui16 Port = 17000; // The port on which to run the web server + TString Host; // DNS entry + const char* ServerName = "YWS/1.0"; // The Web server name to return in HTTP headers + ui32 nThreads = 0; // Thread count for requests processing + ui32 MaxQueueSize = 0; // Max allowed request count in queue ui32 nFThreads = 1; ui32 MaxFQueueSize = 0; ui32 MaxConnections = 100; int ListenBacklog = SOMAXCONN; - TDuration ClientTimeout; + TDuration ClientTimeout; size_t OutputBufferSize = 0; ui64 MaxInputContentLength = sizeof(size_t) <= 4 ? 2_GB : 64_GB; size_t MaxRequestsPerConnection = 0; // If keep-alive is enabled, request limit before connection is closed @@ -173,4 +173,4 @@ public: TString ListenThreadName = "HttpListen"; TString RequestsThreadName = "HttpServer"; TString FailRequestsThreadName = "HttpServer"; -}; +}; diff --git a/library/cpp/http/server/response.cpp b/library/cpp/http/server/response.cpp index 3c7a3e6a93..52d64c91ce 100644 --- a/library/cpp/http/server/response.cpp +++ b/library/cpp/http/server/response.cpp @@ -1,7 +1,7 @@ #include "response.h" - + #include <util/stream/output.h> -#include <util/stream/mem.h> +#include <util/stream/mem.h> #include <util/string/cast.h> THttpResponse& THttpResponse::AddMultipleHeaders(const THttpHeaders& headers) { @@ -11,16 +11,16 @@ THttpResponse& THttpResponse::AddMultipleHeaders(const THttpHeaders& headers) { return *this; } -THttpResponse& THttpResponse::SetContentType(const TStringBuf& contentType) { +THttpResponse& THttpResponse::SetContentType(const TStringBuf& contentType) { Headers.AddOrReplaceHeader(THttpInputHeader("Content-Type", ToString(contentType))); - - return *this; + + return *this; } void THttpResponse::OutTo(IOutputStream& os) const { TVector<IOutputStream::TPart> parts; const size_t FIRST_LINE_PARTS = 3; - const size_t HEADERS_PARTS = Headers.Count() * 4; + const size_t HEADERS_PARTS = Headers.Count() * 4; const size_t CONTENT_PARTS = 5; parts.reserve(FIRST_LINE_PARTS + HEADERS_PARTS + CONTENT_PARTS); @@ -30,20 +30,20 @@ void THttpResponse::OutTo(IOutputStream& os) const { parts.push_back(IOutputStream::TPart::CrLf()); // headers - for (THttpHeaders::TConstIterator i = Headers.Begin(); i != Headers.End(); ++i) { + for (THttpHeaders::TConstIterator i = Headers.Begin(); i != Headers.End(); ++i) { parts.push_back(IOutputStream::TPart(i->Name())); parts.push_back(IOutputStream::TPart(TStringBuf(": "))); parts.push_back(IOutputStream::TPart(i->Value())); parts.push_back(IOutputStream::TPart::CrLf()); } - char buf[50]; - + char buf[50]; + if (!Content.empty()) { - TMemoryOutput mo(buf, sizeof(buf)); + TMemoryOutput mo(buf, sizeof(buf)); mo << Content.size(); - + parts.push_back(IOutputStream::TPart(TStringBuf("Content-Length: "))); parts.push_back(IOutputStream::TPart(buf, mo.Buf() - buf)); parts.push_back(IOutputStream::TPart::CrLf()); @@ -51,15 +51,15 @@ void THttpResponse::OutTo(IOutputStream& os) const { // content parts.push_back(IOutputStream::TPart::CrLf()); - + if (!Content.empty()) { parts.push_back(IOutputStream::TPart(Content)); } os.Write(parts.data(), parts.size()); -} - -template <> +} + +template <> void Out<THttpResponse>(IOutputStream& os, const THttpResponse& resp) { - resp.OutTo(os); + resp.OutTo(os); } diff --git a/library/cpp/http/server/response.h b/library/cpp/http/server/response.h index 7880babac5..a75cb85605 100644 --- a/library/cpp/http/server/response.h +++ b/library/cpp/http/server/response.h @@ -1,8 +1,8 @@ #pragma once - + #include <library/cpp/http/misc/httpcodes.h> #include <library/cpp/http/io/stream.h> - + #include <util/generic/strbuf.h> #include <util/string/cast.h> @@ -12,23 +12,23 @@ class IOutputStream; class THttpResponse { public: THttpResponse() noexcept - : Code(HTTP_OK) - { - } - + : Code(HTTP_OK) + { + } + explicit THttpResponse(HttpCodes code) noexcept : Code(code) { } - template <typename ValueType> + template <typename ValueType> THttpResponse& AddHeader(const TString& name, const ValueType& value) { return AddHeader(THttpInputHeader(name, ToString(value))); } THttpResponse& AddHeader(const THttpInputHeader& header) { Headers.AddHeader(header); - + return *this; } @@ -38,8 +38,8 @@ public: return Headers; } - THttpResponse& SetContentType(const TStringBuf& contentType); - + THttpResponse& SetContentType(const TStringBuf& contentType); + /** * @note If @arg content isn't empty its size is automatically added as a * "Content-Length" header during output to IOutputStream. @@ -47,7 +47,7 @@ public: */ THttpResponse& SetContent(const TString& content) { Content = content; - + return *this; } @@ -61,8 +61,8 @@ public: * @see IOutputStream& operator << (IOutputStream&, const THttpResponse&) */ THttpResponse& SetContent(const TString& content, const TStringBuf& contentType) { - return SetContent(content).SetContentType(contentType); - } + return SetContent(content).SetContentType(contentType); + } HttpCodes HttpCode() const { return Code; diff --git a/library/cpp/http/server/response_ut.cpp b/library/cpp/http/server/response_ut.cpp index ecd41015d9..73e2112ad3 100644 --- a/library/cpp/http/server/response_ut.cpp +++ b/library/cpp/http/server/response_ut.cpp @@ -2,11 +2,11 @@ #include <library/cpp/testing/unittest/registar.h> -#include <util/string/cast.h> - +#include <util/string/cast.h> + Y_UNIT_TEST_SUITE(TestHttpResponse) { Y_UNIT_TEST(TestCodeOnly) { - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse()), "HTTP/1.1 200 Ok\r\n\r\n"); + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse()), "HTTP/1.1 200 Ok\r\n\r\n"); UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse(HTTP_NOT_FOUND)), "HTTP/1.1 404 Not found\r\n\r\n"); } @@ -70,7 +70,7 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { "Content-Length: 10\r\n" "\r\n" "0123456789"; - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("0123456789")), + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("0123456789")), EXPECTED); } @@ -80,8 +80,8 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { "Content-Length: 28\r\n" "\r\n" "<xml><tag value=\"1\" /></xml>"; - THttpResponse resp; - resp.SetContent("<xml><tag value=\"1\" /></xml>").SetContentType("text/xml"); + THttpResponse resp; + resp.SetContent("<xml><tag value=\"1\" /></xml>").SetContentType("text/xml"); UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), EXPECTED); } @@ -90,8 +90,8 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne")) .AddHeader("X-Header-2", "ValueTwo") .AddHeader(THttpInputHeader("X-Header-3", "ValueThree")) - .SetContent("Some stuff") - .SetContentType("text/plain"); + .SetContent("Some stuff") + .SetContentType("text/plain"); THttpResponse copy = resp; UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp)); @@ -102,19 +102,19 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne")); resp.AddHeader(THttpInputHeader("X-Header-2", "ValueTwo")); resp.AddHeader(THttpInputHeader("X-Header-3", "ValueThree")); - resp.SetContent("Some stuff").SetContentType("text/plain"); + resp.SetContent("Some stuff").SetContentType("text/plain"); - THttpResponse copy; + THttpResponse copy; copy = resp; UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp)); } Y_UNIT_TEST(TestEmptyContent) { - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("")), "HTTP/1.1 200 Ok\r\n\r\n"); + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("")), "HTTP/1.1 200 Ok\r\n\r\n"); } Y_UNIT_TEST(TestReturnReference) { - THttpResponse resp; + THttpResponse resp; UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader("Header1", 1)); UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader(THttpInputHeader("Header2", "2"))); @@ -124,7 +124,7 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { UNIT_ASSERT_EQUAL(&resp, &resp.AddMultipleHeaders(headers)); UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some stuff")); - UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some other stuff").SetContentType("text/plain")); + UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some other stuff").SetContentType("text/plain")); } Y_UNIT_TEST(TestSetContentType) { diff --git a/library/cpp/http/server/ut/ya.make b/library/cpp/http/server/ut/ya.make index 17c20a8138..bcb4d4c0b8 100644 --- a/library/cpp/http/server/ut/ya.make +++ b/library/cpp/http/server/ut/ya.make @@ -2,8 +2,8 @@ UNITTEST_FOR(library/cpp/http/server) OWNER(pg) -SIZE(MEDIUM) - +SIZE(MEDIUM) + SRCS( http_ut.cpp response_ut.cpp diff --git a/library/cpp/http/server/ya.make b/library/cpp/http/server/ya.make index 7b6bd59024..bae6f33306 100644 --- a/library/cpp/http/server/ya.make +++ b/library/cpp/http/server/ya.make @@ -1,27 +1,27 @@ -LIBRARY() - -OWNER( - pg +LIBRARY() + +OWNER( + pg mvel kulikov g:base g:middle -) - -SRCS( - conn.cpp - http.cpp - http_ex.cpp - options.cpp +) + +SRCS( + conn.cpp + http.cpp + http_ex.cpp + options.cpp response.cpp -) - +) + PEERDIR( library/cpp/http/misc library/cpp/http/io library/cpp/threading/equeue ) -END() +END() RECURSE_FOR_TESTS(ut) |