"Fossies" - the Fresh Open Source Software Archive

Member "filezilla-3.48.1/src/engine/http/request.cpp" (15 May 2020, 22887 Bytes) of package /linux/misc/FileZilla_3.48.1_src.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "request.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.48.0_vs_3.48.1.

    1 #include <filezilla.h>
    2 
    3 #include "request.h"
    4 
    5 #include <libfilezilla/encode.hpp>
    6 
    7 #include <assert.h>
    8 #include <string.h>
    9 
   10 CHttpRequestOpData::CHttpRequestOpData(CHttpControlSocket & controlSocket, std::shared_ptr<HttpRequestResponseInterface> const& request)
   11     : COpData(PrivCommand::http_request, L"CHttpRequestOpData")
   12     , CHttpOpData(controlSocket)
   13 {
   14     opState = request_init | request_reading;
   15 
   16     request->request().flags_ = 0;
   17     request->response().flags_ = 0;
   18 
   19     requests_.emplace_back(request);
   20 }
   21 
   22 CHttpRequestOpData::CHttpRequestOpData(CHttpControlSocket & controlSocket, std::deque<std::shared_ptr<HttpRequestResponseInterface>> && requests)
   23     : COpData(PrivCommand::http_request, L"CHttpRequestOpData")
   24     , CHttpOpData(controlSocket)
   25     , requests_(requests)
   26 {
   27     for (auto & rr : requests_) {
   28         rr->request().flags_ = 0;
   29         rr->response().flags_ = 0;
   30     }
   31     opState = request_init | request_reading;
   32 }
   33 
   34 void CHttpRequestOpData::AddRequest(std::shared_ptr<HttpRequestResponseInterface> const& rr)
   35 {
   36     if (!(opState & request_send_mask)) {
   37         bool wait = false;
   38         if (!requests_.empty()) {
   39             if (!requests_.back() && !read_state_.keep_alive_) {
   40                 wait = true;
   41             }
   42             else if (requests_.back() && !(requests_.back()->request().keep_alive() || requests_.back()->response().keep_alive())) {
   43                 wait = true;
   44             }
   45         }
   46         if (wait) {
   47             opState |= request_send_wait_for_read;
   48         }
   49         else {
   50             opState |= request_init;
   51             if (controlSocket_.active_layer_) {
   52                 controlSocket_.send_event<fz::socket_event>(controlSocket_.active_layer_, fz::socket_event_flag::write, 0);
   53             }
   54         }
   55     }
   56     rr->request().flags_ = 0;
   57     rr->response().flags_ = 0;
   58     requests_.push_back(rr);
   59 }
   60 
   61 int CHttpRequestOpData::Send()
   62 {
   63     if (opState & request_init) {
   64         if (send_pos_ >= requests_.size()) {
   65             opState &= ~request_init;
   66             return FZ_REPLY_CONTINUE;
   67         }
   68 
   69         auto & rr = *requests_[send_pos_];
   70         auto & req = rr.request();
   71 
   72         // Check backoff
   73         fz::duration backoff = controlSocket_.throttler_.get_throttle(req.uri_.host_);
   74         if (backoff) {
   75             if (backoff >= fz::duration::from_seconds(30)) {
   76                 log(logmsg::status, _("Server instructed us to wait %d seconds before sending next request"), backoff.get_seconds());
   77             }
   78             controlSocket_.Sleep(backoff);
   79             return FZ_REPLY_CONTINUE;
   80         }
   81 
   82         int res = req.reset();
   83         if (res != FZ_REPLY_CONTINUE) {
   84             return res;
   85         }
   86 
   87         res = rr.response().reset();
   88         if (res != FZ_REPLY_CONTINUE) {
   89             return res;
   90         }
   91 
   92         if (req.verb_.empty()) {
   93             log(logmsg::debug_warning, L"No request verb");
   94             return FZ_REPLY_INTERNALERROR;
   95         }
   96         std::string host_header = req.uri_.host_;
   97         if (req.uri_.port_ != 0) {
   98             host_header += ':';
   99             host_header += fz::to_string(req.uri_.port_);
  100         }
  101         req.headers_["Host"] = host_header;
  102         auto pos = req.headers_.find("Connection");
  103         if (pos == req.headers_.end()) {
  104             // TODO: consider making keep-alive the default
  105             req.headers_["Connection"] = "close";
  106         }
  107         req.headers_["User-Agent"] = fz::replaced_substrings(PACKAGE_STRING, " ", "/");
  108 
  109         opState &= ~request_init;
  110         opState |= request_wait_connect;
  111         return FZ_REPLY_CONTINUE;
  112     }
  113 
  114     if (opState & request_send_wait_for_read) {
  115         if (send_pos_ > 0) {
  116             return FZ_REPLY_WOULDBLOCK;
  117         }
  118 
  119         opState &= ~request_send_wait_for_read;
  120         opState |= request_init;
  121 
  122         return FZ_REPLY_CONTINUE;
  123     }
  124 
  125     if (opState & request_wait_connect) {
  126         if (send_pos_ >= requests_.size()) {
  127             log(logmsg::debug_warning, L"Bad state: opState & request_wait_connect yet send_pos_ >= requests_.size()");
  128             return FZ_REPLY_INTERNALERROR;
  129         }
  130 
  131         auto & rr = *requests_[send_pos_];
  132         auto & req = rr.request();
  133 
  134         auto const& uri = req.uri_;
  135         int res = controlSocket_.InternalConnect(fz::to_wstring_from_utf8(uri.host_), uri.port_, uri.scheme_ == "https", !send_pos_);
  136         if (res == FZ_REPLY_OK) {
  137             opState &= ~request_wait_connect;
  138             opState |= request_send;
  139             res = FZ_REPLY_CONTINUE;
  140         }
  141         return res;
  142     }
  143 
  144     if (opState & request_send) {
  145         if (send_pos_ >= requests_.size()) {
  146             opState &= ~request_send;
  147         }
  148         else if (!requests_[send_pos_]) {
  149             log(logmsg::debug_warning, L"Null request in request_send state.");
  150             return FZ_REPLY_INTERNALERROR;
  151         }
  152         else {
  153             auto & req = requests_[send_pos_]->request();
  154             if (!(req.flags_ & HttpRequest::flag_sent_header)) {
  155                 if (req.body_) {
  156                     req.set_content_length(req.body_->size());
  157                 }
  158                 else {
  159                     if (req.verb_ == "GET" || req.verb_ == "HEAD" || req.verb_ == "OPTIONS") {
  160                         req.headers_.erase("Content-Length");
  161                     }
  162                     else {
  163                         req.set_content_length(0);
  164                     }
  165                 }
  166 
  167                 auto const cl = req.get_header("Content-Length");
  168                 if (!cl.empty()) {
  169                     int64_t requestContentLength = fz::to_integral<int64_t>(cl, -1);
  170                     if (requestContentLength < 0) {
  171                         log(logmsg::error, _("Malformed request header: %s"), _("Invalid Content-Length"));
  172                         return FZ_REPLY_INTERNALERROR;
  173                     }
  174                     dataToSend_ = static_cast<uint64_t>(requestContentLength);
  175                 }
  176 
  177                 // Assemble request and headers
  178                 std::string command = fz::sprintf("%s %s HTTP/1.1", req.verb_, req.uri_.get_request());
  179                 log(logmsg::command, "%s", command);
  180                 command += "\r\n";
  181 
  182                 for (auto const& header : req.headers_) {
  183                     std::string line = fz::sprintf("%s: %s", header.first, header.second);
  184                     if (header.first == "Authorization") {
  185                         log(logmsg::command, "%s: %s", header.first, std::string(header.second.size(), '*'));
  186                     }
  187                     else {
  188                         log(logmsg::command, "%s", line);
  189                     }
  190                     command += line + "\r\n";
  191                 }
  192 
  193                 command += "\r\n";
  194 
  195                 req.flags_ |= HttpRequest::flag_sent_header;
  196                 if (!req.body_) {
  197                     log(logmsg::debug_info, "Finished sending request header. Request has no body");
  198                     opState &= ~request_send;
  199                     ++send_pos_;
  200                     if (send_pos_ < requests_.size()) {
  201                         if (!req.keep_alive()) {
  202                             opState |= request_send_wait_for_read;
  203                             log(logmsg::debug_info, L"Request did not ask for keep-alive. Waiting for response to finish before sending next request a new connection.");
  204                         }
  205                         else {
  206                             opState |= request_init;
  207                         }
  208                     }
  209                 }
  210                 else {
  211                     log(logmsg::debug_info, "Finished sending request header.");
  212                     sendLogLevel_ = logmsg::debug_debug;
  213 
  214                     // Disable Nagle's algorithm if we have a beefy body
  215                     if (req.body_->size() > 536) { // TCPv4 minimum required MSS
  216                         controlSocket_.socket_->set_flags(fz::socket::flag_nodelay, false);
  217                     }
  218                 }
  219 
  220                 auto result = controlSocket_.Send(command.c_str(), command.size());
  221                 if (result == FZ_REPLY_WOULDBLOCK && !controlSocket_.send_buffer_) {
  222                     result = FZ_REPLY_CONTINUE;
  223                 }
  224 
  225                 return result;
  226             }
  227             else {
  228                 int const chunkSize = 65536;
  229 
  230                 while (dataToSend_ || controlSocket_.send_buffer_) {
  231                     if (!controlSocket_.send_buffer_) {
  232                         unsigned int len = chunkSize;
  233                         if (chunkSize > dataToSend_) {
  234                             len = static_cast<unsigned int>(dataToSend_);
  235                         }
  236                         int res = req.body_->data_request(controlSocket_.send_buffer_.get(len), len);
  237                         if (res != FZ_REPLY_CONTINUE) {
  238                             return res;
  239                         }
  240                         if (len > dataToSend_) {
  241                             log(logmsg::debug_warning, L"req.body_ returned too much data");
  242                             return FZ_REPLY_INTERNALERROR;
  243                         }
  244 
  245                         controlSocket_.send_buffer_.add(len);
  246                         dataToSend_ -= len;
  247                     }
  248 
  249                     int error;
  250                     int written = controlSocket_.active_layer_->write(controlSocket_.send_buffer_.get(), controlSocket_.send_buffer_.size(), error);
  251                     if (written < 0) {
  252                         if (error != EAGAIN) {
  253                             log(logmsg::error, _("Could not write to socket: %s"), fz::socket_error_description(error));
  254                             log(logmsg::error, _("Disconnected from server"));
  255                             return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  256                         }
  257                         return FZ_REPLY_WOULDBLOCK;
  258                     }
  259 
  260                     if (written) {
  261                         controlSocket_.SetActive(CFileZillaEngine::send);
  262 
  263                         controlSocket_.send_buffer_.consume(static_cast<size_t>(written));
  264                     }
  265                 }
  266 
  267                 log(logmsg::debug_info, "Finished sending request body");
  268 
  269                 controlSocket_.socket_->set_flags(fz::socket::flag_nodelay, true);
  270 
  271                 req.flags_ |= HttpRequest::flag_sent_body;
  272 
  273                 sendLogLevel_ = logmsg::debug_verbose;
  274 
  275                 opState &= ~request_send;
  276                 ++send_pos_;
  277 
  278                 if (send_pos_ < requests_.size()) {
  279                     if (!req.keep_alive()) {
  280                         opState |= request_send_wait_for_read;
  281                         log(logmsg::debug_info, L"Request did not ask for keep-alive. Waiting for response to finish before sending next request a new connection.");
  282                     }
  283                     else {
  284                         opState |= request_init;
  285                     }
  286                 }
  287                 return FZ_REPLY_CONTINUE;
  288             }
  289         }
  290     }
  291     
  292     if (opState & request_reading) {
  293         return FZ_REPLY_WOULDBLOCK;
  294     }
  295     
  296     return FZ_REPLY_INTERNALERROR;
  297 }
  298 
  299 int CHttpRequestOpData::SubcommandResult(int, COpData const&)
  300 {
  301     if (opState & request_wait_connect) {
  302         opState &= ~request_wait_connect;
  303         opState |= request_send;
  304     }
  305 
  306     return FZ_REPLY_CONTINUE;
  307 }
  308 
  309 int CHttpRequestOpData::ParseReceiveBuffer(bool eof)
  310 {
  311     auto & shared_response = requests_.front();
  312     if (shared_response) {
  313         auto & request = shared_response->request();
  314         if (!(request.flags_ & HttpRequest::flag_sent_header)) {
  315             if (eof) {
  316                 log(logmsg::debug_verbose, L"Socket closed before request got sent");
  317                 log(logmsg::error, _("Connection closed by server"));
  318                 return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  319             }
  320             else if (!recv_buffer_.empty()) {
  321                 log(logmsg::error, _("Server sent data even before request headers were sent"));
  322                 return FZ_REPLY_ERROR;
  323             }
  324         }
  325         auto & response = shared_response->response();
  326 
  327         if (!response.got_header()) {
  328             if (eof) {
  329                 log(logmsg::debug_verbose, L"Socket closed before headers got received");
  330                 log(logmsg::error, _("Connection closed by server"));
  331                 return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  332             }
  333 
  334             return ParseHeader();
  335         }
  336     }
  337 
  338     if (read_state_.transfer_encoding_ == chunked) {
  339         if (eof) {
  340             log(logmsg::debug_verbose, L"Socket closed, chunk incomplete");
  341             log(logmsg::error, _("Connection closed by server"));
  342             return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  343         }
  344         return ParseChunkedData();
  345     }
  346     else {
  347         if (eof) {
  348             assert(recv_buffer_.empty());
  349 
  350             if (read_state_.responseContentLength_ != -1 && read_state_.receivedData_ != read_state_.responseContentLength_) {
  351                 log(logmsg::debug_verbose, L"Socket closed, content length not reached");
  352                 log(logmsg::error, _("Connection closed by server"));
  353                 return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  354             }
  355             else {
  356                 if (shared_response) {
  357                     shared_response->response().flags_ |= HttpResponse::flag_got_body;
  358                 }
  359                 return FZ_REPLY_OK;
  360             }
  361         }
  362         else {
  363             size_t size = recv_buffer_.size();
  364             if (!size) {
  365                 return FZ_REPLY_WOULDBLOCK;
  366             }
  367 
  368             if (read_state_.responseContentLength_ != -1 && read_state_.receivedData_ + static_cast<int64_t>(size) > read_state_.responseContentLength_) {
  369                 size = static_cast<size_t>(read_state_.responseContentLength_ - read_state_.receivedData_);
  370             }
  371 
  372             int res = ProcessData(recv_buffer_.get(), size);
  373             recv_buffer_.consume(size);
  374             return res;
  375         }
  376     }
  377 
  378     return FZ_REPLY_INTERNALERROR;
  379 }
  380 
  381 int CHttpRequestOpData::OnReceive()
  382 {
  383     while (controlSocket_.socket_) {
  384         int error;
  385         size_t const recv_size = 1024 * 64;
  386         int read = controlSocket_.active_layer_->read(recv_buffer_.get(recv_size), recv_size, error);
  387         if (read <= -1) {
  388             if (error != EAGAIN) {
  389                 log(logmsg::error, _("Could not read from socket: %s"), fz::socket_error_description(error));
  390                 return FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED;
  391             }
  392             return FZ_REPLY_WOULDBLOCK;
  393         }
  394         recv_buffer_.add(static_cast<size_t>(read));
  395 
  396         controlSocket_.SetActive(CFileZillaEngine::recv);
  397 
  398         bool const eof = read == 0;
  399 
  400         while (!requests_.empty()) {
  401             assert(!requests_.empty());
  402 
  403             int res = ParseReceiveBuffer(eof);
  404             if (res == FZ_REPLY_WOULDBLOCK) {
  405                 break;
  406             }
  407 
  408             if (res == FZ_REPLY_OK) {
  409                 log(logmsg::debug_info, L"Finished a response");
  410                 requests_.pop_front();
  411                 --send_pos_;
  412 
  413                 bool keep_alive = read_state_.keep_alive_;
  414                 if (!keep_alive || eof) {
  415                     if (!recv_buffer_.empty()) {
  416                         log(logmsg::error, _("Malformed response: %s"), _("Server sent too much data."));
  417                         return FZ_REPLY_ERROR;
  418                     }
  419 
  420                     controlSocket_.ResetSocket();
  421                 }
  422 
  423                 read_state_ = read_state();
  424 
  425                 if (requests_.empty()) {
  426                     log(logmsg::debug_info, L"Done reading last response");
  427                     opState &= ~request_reading;
  428 
  429                     if (!recv_buffer_.empty()) {
  430                         log(logmsg::error, _("Malformed response: %s"), _("Server sent too much data."));
  431                         return FZ_REPLY_ERROR;
  432                     }
  433                     return FZ_REPLY_OK;
  434                 }
  435 
  436                 if (!keep_alive || eof) {
  437                     send_pos_ = 0;
  438                     opState = request_init | request_reading;
  439                     return FZ_REPLY_CONTINUE;
  440                 }
  441             }
  442             else if (res != FZ_REPLY_CONTINUE) {
  443                 return res;
  444             }
  445         }
  446 
  447         if (requests_.empty() && !recv_buffer_.empty()) {
  448             log(logmsg::error, _("Malformed response: %s"), _("Server sent too much data."));
  449             return FZ_REPLY_ERROR;
  450         }
  451     }
  452 
  453     return FZ_REPLY_WOULDBLOCK;
  454 }
  455 
  456 int CHttpRequestOpData::ParseHeader()
  457 {
  458     log(logmsg::debug_verbose, L"CHttpRequestOpData::ParseHeader()");
  459 
  460     // Parse the HTTP header.
  461     // We do just the neccessary parsing and silently ignore most header fields
  462     // The calling operation is responsible for things like redirect parsing.
  463     for (;;) {
  464         // Find line ending
  465         size_t i = 0;
  466         for (i = 0; (i + 1) < recv_buffer_.size(); ++i) {
  467             if (recv_buffer_[i] == '\r') {
  468                 if (recv_buffer_[i + 1] != '\n') {
  469                     log(logmsg::error, _("Malformed response header: %s"), _("Server not sending proper line endings"));
  470                     return FZ_REPLY_ERROR;
  471                 }
  472                 break;
  473             }
  474             if (!recv_buffer_[i]) {
  475                 log(logmsg::error, _("Malformed response header: %s"), _("Null character in line"));
  476                 return FZ_REPLY_ERROR;
  477             }
  478         }
  479         if ((i + 1) >= recv_buffer_.size()) {
  480             size_t const max_line_size = 8192;
  481             if (recv_buffer_.size() >= max_line_size) {
  482                 log(logmsg::error, _("Too long header line"));
  483                 return FZ_REPLY_ERROR;
  484             }
  485             return FZ_REPLY_WOULDBLOCK;
  486         }
  487 
  488         std::wstring wline = fz::to_wstring_from_utf8(reinterpret_cast<char const*>(recv_buffer_.get()), i);
  489         if (wline.empty()) {
  490             wline = fz::to_wstring(std::string(recv_buffer_.get(), recv_buffer_.get() + i));
  491         }
  492         if (!wline.empty()) {
  493             controlSocket_.log_raw(logmsg::reply, wline);
  494         }
  495 
  496         auto & response = requests_.front()->response();
  497         if (!response.got_code()) {
  498             if (recv_buffer_.size() < 15 || memcmp(recv_buffer_.get(), "HTTP/1.", 7)) {
  499                 // Invalid HTTP Status-Line
  500                 log(logmsg::error, _("Invalid HTTP Response"));
  501                 return FZ_REPLY_ERROR;
  502             }
  503 
  504             if (recv_buffer_[9] < '1' || recv_buffer_[9] > '5' ||
  505                 recv_buffer_[10] < '0' || recv_buffer_[10] > '9' ||
  506                 recv_buffer_[11] < '0' || recv_buffer_[11] > '9')
  507             {
  508                 // Invalid response code
  509                 log(logmsg::error, _("Invalid response code"));
  510                 return FZ_REPLY_ERROR;
  511             }
  512 
  513             response.code_ = (recv_buffer_[9] - '0') * 100 + (recv_buffer_[10] - '0') * 10 + recv_buffer_[11] - '0';
  514             response.flags_ |= HttpResponse::flag_got_code;
  515         }
  516         else {
  517             if (!i) {
  518                 recv_buffer_.consume(2);
  519 
  520                 // End of header
  521                 return ProcessCompleteHeader();
  522             }
  523 
  524             std::string line(recv_buffer_.get(), recv_buffer_.get() + i);
  525 
  526             auto delim_pos = line.find(':');
  527             if (delim_pos == std::string::npos || !delim_pos) {
  528                 log(logmsg::error, _("Malformed response header: %s"), _("Invalid line"));
  529                 return FZ_REPLY_ERROR;
  530             }
  531 
  532             std::string value;
  533             auto value_start = line.find_first_not_of(" \t", delim_pos + 1);
  534             if (value_start != std::string::npos) {
  535                 int value_stop = line.find_last_not_of(" \t"); // Cannot fail
  536                 value = line.substr(value_start, value_stop - value_start + 1);
  537             }
  538 
  539             auto & header = response.headers_[line.substr(0, delim_pos)];
  540             if (header.empty()) {
  541                 header = value;
  542             }
  543             else if (!value.empty()) {
  544                 header += ", " + value;
  545             }
  546         }
  547 
  548         recv_buffer_.consume(i + 2);
  549 
  550         if (recv_buffer_.empty()) {
  551             break;
  552         }
  553     }
  554 
  555     return FZ_REPLY_WOULDBLOCK;
  556 }
  557 
  558 int CHttpRequestOpData::ProcessCompleteHeader()
  559 {
  560     log(logmsg::debug_verbose, L"CHttpRequestOpData::ParseHeader()");
  561 
  562     auto & srr = requests_.front();
  563     auto & request = srr->request();
  564     auto & response = srr->response();
  565     if (response.code_ == 100) {
  566         // 100 Continue header. Ignore it and start over.
  567         response.reset();
  568         return FZ_REPLY_CONTINUE;
  569     }
  570 
  571     response.flags_ |= HttpResponse::flag_got_header;
  572     if (request.verb_ == "HEAD" || response.code_prohobits_body()) {
  573         response.flags_ |= HttpResponse::flag_no_body;
  574     }
  575 
  576     auto const te = fz::str_tolower_ascii(response.get_header("Transfer-Encoding"));
  577     if (te == "chunked") {
  578         read_state_.transfer_encoding_ = chunked;
  579     }
  580     else if (te.empty() || te == "identity") {
  581         read_state_.transfer_encoding_ = identity;
  582     }
  583     else {
  584         log(logmsg::error, _("Malformed response header: %s"), _("Unknown transfer encoding"));
  585         return FZ_REPLY_ERROR;
  586     }
  587     
  588     auto retry = response.get_header("Retry-After");
  589     if (response.code_ >= 400 && !retry.empty()) {
  590         // TODO: Retry-After for redirects
  591         auto const now = fz::datetime::now();
  592 
  593         fz::duration d;
  594         int seconds = fz::to_integral<int>(retry, -1);
  595         if (seconds > 0) {
  596             d = fz::duration::from_seconds(seconds);
  597         }
  598         else {
  599             fz::datetime t;
  600             if (t.set_rfc822(retry)) {
  601                 if (t > now) {
  602                     d = t - now;
  603                 }
  604             }
  605         }
  606 
  607         if (!d && response.code_ == 429) {
  608             d = fz::duration::from_seconds(1);
  609         }
  610         if (d) {
  611             log(logmsg::debug_verbose, "Got Retry-After with %d", d.get_seconds());
  612             controlSocket_.throttler_.throttle(request.uri_.host_, now + d);
  613         }
  614     }
  615 
  616     int64_t length{-1};
  617     auto const cl = response.get_header("Content-Length");
  618     if (!cl.empty()) {
  619         length = fz::to_integral<int64_t>(cl, -1);
  620         if (length < 0) {
  621             log(logmsg::error, _("Malformed response header: %s"), _("Invalid Content-Length"));
  622             return FZ_REPLY_ERROR;
  623         }
  624     }
  625 
  626     if (response.no_body()) {
  627         read_state_.responseContentLength_ = 0;
  628     }
  629     else {
  630         read_state_.responseContentLength_ = length;
  631     }
  632 
  633     read_state_.keep_alive_ = response.keep_alive() && request.keep_alive();
  634 
  635     int res = FZ_REPLY_CONTINUE;
  636     if (response.on_header_) {
  637         res = response.on_header_(srr);
  638 
  639         if (res != FZ_REPLY_CONTINUE) {
  640             if (res == FZ_REPLY_OK) {
  641                 if (!request.body_ || request.flags_ & HttpRequest::flag_sent_body) {
  642                     // Clear the pointer, we no longer need the request to finish, all needed information is in read_state_
  643                     srr.reset();
  644                 }
  645                 res = FZ_REPLY_CONTINUE;
  646             }
  647             else {
  648                 response.flags_ |= HttpResponse::flag_ignore_body;
  649             }
  650         }
  651     }
  652 
  653     if (res == FZ_REPLY_CONTINUE) {
  654         if (!read_state_.responseContentLength_) {
  655             res = FZ_REPLY_OK;
  656         }
  657     }
  658 
  659     return res;
  660 }
  661 
  662 int CHttpRequestOpData::ParseChunkedData()
  663 {
  664     while (!recv_buffer_.empty()) {
  665         if (read_state_.chunk_data_.size != 0) {
  666             size_t dataLen = recv_buffer_.size();
  667             if (read_state_.chunk_data_.size < recv_buffer_.size()) {
  668                 dataLen = static_cast<size_t>(read_state_.chunk_data_.size);
  669             }
  670             int res = ProcessData(recv_buffer_.get(), dataLen);
  671             if (res != FZ_REPLY_CONTINUE) {
  672                 return res;
  673             }
  674             recv_buffer_.consume(dataLen);
  675             read_state_.chunk_data_.size -= dataLen;
  676 
  677             if (read_state_.chunk_data_.size == 0) {
  678                 read_state_.chunk_data_.terminateChunk = true;
  679             }
  680         }
  681 
  682         // Find line ending
  683         size_t i = 0;
  684         for (i = 0; (i + 1) < recv_buffer_.size(); ++i) {
  685             if (recv_buffer_[i] == '\r') {
  686                 if (recv_buffer_[i + 1] != '\n') {
  687                     log(logmsg::error, _("Malformed chunk data: %s"), _("Wrong line endings"));
  688                     return FZ_REPLY_ERROR;
  689                 }
  690                 break;
  691             }
  692             if (!recv_buffer_[i]) {
  693                 log(logmsg::error, _("Malformed chunk data: %s"), _("Null character in line"));
  694                 return FZ_REPLY_ERROR;
  695             }
  696         }
  697         if ((i + 1) >= recv_buffer_.size()) {
  698             size_t const max_line_size = 8192;
  699             if (recv_buffer_.size() >= max_line_size) {
  700                 log(logmsg::error, _("Malformed chunk data: %s"), _("Line length exceeded"));
  701                 return FZ_REPLY_ERROR;
  702             }
  703             break;
  704         }
  705 
  706         if (read_state_.chunk_data_.terminateChunk) {
  707             if (i) {
  708                 // The chunk data has to end with CRLF. If i is nonzero,
  709                 // it didn't end with just CRLF.
  710                 log(logmsg::debug_debug, L"%u characters preceeding line-ending with value %s", i, fz::hex_encode<std::string>(std::string(recv_buffer_.get(), recv_buffer_.get() + recv_buffer_.size())));
  711                 log(logmsg::error, _("Malformed chunk data: %s"), _("Chunk data improperly terminated"));
  712                 return FZ_REPLY_ERROR;
  713             }
  714             read_state_.chunk_data_.terminateChunk = false;
  715         }
  716         else if (read_state_.chunk_data_.getTrailer) {
  717             if (!i) {
  718                 // We're done
  719                 recv_buffer_.consume(2);
  720 
  721                 auto & response = requests_.front();
  722                 if (response) {
  723                     response->response().flags_ |= HttpResponse::flag_got_body;
  724                 }
  725                 return FZ_REPLY_OK;
  726             }
  727 
  728             // Ignore the trailer
  729         }
  730         else {
  731             // Read chunk size
  732             unsigned char const* end = recv_buffer_.get() + i;
  733             for (unsigned char* q = recv_buffer_.get(); q != end && *q != ';' && *q != ' '; ++q) {
  734                 read_state_.chunk_data_.size *= 16;
  735                 if (*q >= '0' && *q <= '9') {
  736                     read_state_.chunk_data_.size += *q - '0';
  737                 }
  738                 else if (*q >= 'A' && *q <= 'F') {
  739                     read_state_.chunk_data_.size += *q - 'A' + 10;
  740                 }
  741                 else if (*q >= 'a' && *q <= 'f') {
  742                     read_state_.chunk_data_.size += *q - 'a' + 10;
  743                 }
  744                 else {
  745                     // Invalid size
  746                     log(logmsg::error, _("Malformed chunk data: %s"), _("Invalid chunk size"));
  747                     return FZ_REPLY_ERROR;
  748                 }
  749             }
  750             if (!read_state_.chunk_data_.size) {
  751                 read_state_.chunk_data_.getTrailer = true;
  752             }
  753         }
  754 
  755         recv_buffer_.consume(i + 2);
  756     }
  757 
  758     return FZ_REPLY_WOULDBLOCK;
  759 }
  760 
  761 int CHttpRequestOpData::ProcessData(unsigned char* data, unsigned int len)
  762 {
  763     read_state_.receivedData_ += len;
  764 
  765     int res = FZ_REPLY_CONTINUE;
  766 
  767     auto & shared_response = requests_.front();
  768     if (shared_response) {
  769         auto & response = shared_response->response();
  770 
  771         decltype(response.on_data_) *on_data = nullptr;
  772 
  773         if (response.on_data_ && !(response.flags_ & HttpResponse::flag_ignore_body)) {
  774             on_data = &response.on_data_;
  775         }
  776 
  777         if (response.on_error_data_ && !response.success() && !(response.flags_ & HttpResponse::flag_ignore_body)) {
  778             on_data = &response.on_error_data_;
  779         }
  780 
  781         if (on_data) {
  782             res = (*on_data)(data, len);
  783         }
  784     }
  785 
  786     if (res == FZ_REPLY_CONTINUE && read_state_.receivedData_ == read_state_.responseContentLength_) {
  787         if (shared_response) {
  788             shared_response->response().flags_ |= HttpResponse::flag_got_body;
  789         }
  790         res = FZ_REPLY_OK;
  791     }
  792 
  793     return res;
  794 }
  795 
  796 int CHttpRequestOpData::Reset(int result)
  797 {
  798     if (result != FZ_REPLY_OK) {
  799         controlSocket_.ResetSocket();
  800     }
  801     else if (opState != request_done) {
  802         controlSocket_.ResetSocket();
  803     }
  804     else if (!recv_buffer_.empty()) {
  805         log(logmsg::debug_verbose, L"Closing connection, the receive buffer isn't empty but at %d", recv_buffer_.size());
  806         controlSocket_.ResetSocket();
  807     }
  808     else {
  809         if (controlSocket_.active_layer_) {
  810             controlSocket_.send_event<fz::socket_event>(controlSocket_.active_layer_, fz::socket_event_flag::read, 0);
  811         }
  812     }
  813 
  814     return result;
  815 }