void Connection::handleWriteResponse(ReplyPtr reply) { LOG_DEBUG(socket().native() << ": handleWriteResponse() " << haveResponse_ << " " << responseDone_); if (haveResponse_) startWriteResponse(reply); else { if (!responseDone_) { /* * Keep reply open and wait for more data. */ } else { reply->logReply(request_handler_.logger()); if (reply->closeConnection()) ConnectionManager_.stop(shared_from_this()); else { request_parser_.reset(); request_.reset(); responseDone_ = false; while (rcv_buffers_.size() > 1) rcv_buffers_.pop_front(); if (rcv_remaining_ < rcv_buffers_.back().data() + rcv_buffer_size_) handleReadRequest0(); else startAsyncReadRequest(rcv_buffers_.back(), KEEPALIVE_TIMEOUT); } } } }
bool RequestParser::parseBody(Request& req, ReplyPtr reply, Buffer::iterator& begin, Buffer::iterator end) { if (req.webSocketVersion >= 0) { Request::State state = parseWebSocketMessage(req, reply, begin, end); if (state == Request::Error) reply->consumeData(begin, begin, Request::Error); return state != Request::Partial; } else { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); Buffer::iterator thisBegin = begin; Buffer::iterator thisEnd = begin + thisSize; remainder_ -= thisSize; begin = thisEnd; bool endOfRequest = remainder_ == 0; reply->consumeData(thisBegin, thisEnd, endOfRequest ? Request::Complete : Request::Partial); if (reply->status() == Reply::request_entity_too_large) return true; else return endOfRequest; } }
void Connection::sendStockReply(StockReply::status_type status) { ReplyPtr reply (new StockReply(request_, status, "", server_->configuration())); reply->setConnection(shared_from_this()); reply->setCloseConnection(); startWriteResponse(reply); }
RequestParser::ParseResult RequestParser::parseBody(Request& req, ReplyPtr reply, Buffer::iterator& begin, Buffer::iterator end) { if (req.type == Request::WebSocket) { Request::State state = parseWebSocketMessage(req, reply, begin, end); if (state == Request::Error) reply->consumeData(begin, begin, Request::Error); return state == Request::Partial ? ReadMore : Done; } else if (req.type == Request::TCP) { ::int64_t thisSize = (::int64_t)(end - begin); Buffer::iterator thisBegin = begin; Buffer::iterator thisEnd = begin + thisSize; begin = thisEnd; bool canReadMore = reply->consumeData(thisBegin, thisEnd, Request::Partial); if (reply->status() == Reply::request_entity_too_large) return Done; else if (canReadMore) return ReadMore; else return NotReady; } else { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); Buffer::iterator thisBegin = begin; Buffer::iterator thisEnd = begin + thisSize; remainder_ -= thisSize; begin = thisEnd; bool endOfRequest = remainder_ == 0; bool canReadMore = reply->consumeData(thisBegin, thisEnd, endOfRequest ? Request::Complete : Request::Partial); if (reply->status() == Reply::request_entity_too_large) return Done; else if (endOfRequest) return Done; else if (canReadMore) return ReadMore; else return NotReady; } }
void Connection::handleReadBody(ReplyPtr reply, const asio_error_code& e, std::size_t bytes_transferred) { LOG_DEBUG(socket().native() << ": handleReadBody(): " << e.message()); if (disconnectCallback_) { if (e && e != asio::error::operation_aborted) { boost::function<void()> f = disconnectCallback_; disconnectCallback_ = boost::function<void()>(); f(); } else if (e != asio::error::operation_aborted) { LOG_ERROR(socket().native() << ": handleReadBody(): while waiting for disconnect, " "unexpected error code: " << e.message()); close(); } return; } cancelReadTimer(); if (!e) { rcv_remaining_ = rcv_buffers_.back().data(); rcv_buffer_size_ = bytes_transferred; handleReadBody(reply); } else if (e != asio::error::operation_aborted && e != asio::error::bad_descriptor) { reply->consumeData(rcv_remaining_, rcv_remaining_, Request::Error); handleError(e); } }
void Connection::startWriteResponse(ReplyPtr reply) { haveResponse_ = false; if (disconnectCallback_) socket().cancel(); if (state_ & Writing) { LOG_ERROR("Connection::startWriteResponse(): connection already writing"); close(); server_->service() .post(strand_.wrap(boost::bind(&Reply::writeDone, reply, false))); return; } std::vector<asio::const_buffer> buffers; responseDone_ = reply->nextBuffers(buffers); unsigned s = 0; #ifdef DEBUG for (unsigned i = 0; i < buffers.size(); ++i) { int size = asio::buffer_size(buffers[i]); s += size; #ifdef DEBUG_DUMP char *data = (char *)asio::detail::buffer_cast_helper(buffers[i]); for (int j = 0; j < size; ++j) std::cerr << data[j]; #endif } #endif LOG_DEBUG(socket().native() << " sending: " << s << "(buffers: " << buffers.size() << ")"); if (!buffers.empty()) { startAsyncWriteResponse(reply, buffers, BODY_TIMEOUT); } else { cancelWriteTimer(); handleWriteResponse(reply); } }
void Connection::handleWriteResponse(ReplyPtr reply, const asio_error_code& e, std::size_t bytes_transferred) { LOG_DEBUG(socket().native() << ": handleWriteResponse(): " << bytes_transferred << " ; " << e.message()); cancelWriteTimer(); haveResponse_ = false; waitingResponse_ = true; reply->writeDone(!e); waitingResponse_ = false; if (!e) { handleWriteResponse(reply); } else { if (e != asio::error::operation_aborted) handleError(e); } }
Request::State RequestParser::parseWebSocketMessage(Request& req, ReplyPtr reply, Buffer::iterator& begin, Buffer::iterator end) { switch (wsState_) { case ws_start: { if (req.webSocketVersion != 0 && req.webSocketVersion != 7 && req.webSocketVersion != 8 && req.webSocketVersion != 13) { LOG_ERROR("ws: unsupported protocol version " << req.webSocketVersion); // FIXME add Sec-WebSocket-Version fields return Request::Error; } if (req.webSocketVersion == 0) { LOG_INFO("ws: connect with protocol version 0"); /* * In version 00, the hand shake is two-staged, we first need to * send the 101 to be able to access the part of the handshake * that is sent after the GET */ const Request::Header *host = req.getHeader("Host"); if (!host || host->value.empty()) { LOG_ERROR("ws: missing Host field"); return Request::Error; } wsState_ = ws00_hand_shake; wsCount_ = 0; reply->setStatus(Reply::switching_protocols); reply->addHeader("Connection", "Upgrade"); reply->addHeader("Upgrade", "WebSocket"); const Request::Header *origin = req.getHeader("Origin"); if (origin && !origin->value.empty()) reply->addHeader("Sec-WebSocket-Origin", origin->value.str()); std::string location = std::string(req.urlScheme) + "://" + host->value.str() + req.request_path + "?" + req.request_query; reply->addHeader("Sec-WebSocket-Location", location); reply->consumeData(begin, begin, Request::Partial); return Request::Complete; } else { LOG_INFO("ws: connect with protocol version " << req.webSocketVersion); std::string accept = doWebSocketHandshake13(req); if (accept.empty()) { LOG_ERROR("ws: error computing handshake result"); return Request::Error; } else { wsState_ = ws13_frame_start; reply->setStatus(Reply::switching_protocols); reply->addHeader("Connection", "Upgrade"); reply->addHeader("Upgrade", "WebSocket"); reply->addHeader("Sec-WebSocket-Accept", accept); reply->consumeData(begin, begin, Request::Complete); return Request::Complete; } } break; } case ws00_hand_shake: { unsigned thisSize = std::min((::int64_t)(end - begin), (::int64_t)(8 - wsCount_)); memcpy(ws00_buf_ + wsCount_, begin, thisSize); wsCount_ += thisSize; begin += thisSize; if (wsCount_ == 8) { bool okay = doWebSocketHandshake00(req); if (okay) { wsState_ = ws00_frame_start; reply->consumeData(ws00_buf_, ws00_buf_ + 16, Request::Complete); return Request::Complete; } else { LOG_ERROR("ws: invalid client hand-shake"); return Request::Error; } } else return Request::Partial; } default: break; } Buffer::iterator dataBegin = begin; Buffer::iterator dataEnd = begin; // Initially assume no data Request::State state = Request::Partial; while (begin < end && state == Request::Partial) { switch (wsState_) { case ws00_frame_start: wsFrameType_ = *begin; if (wsFrameType_ & 0x80) { wsState_ = ws00_binary_length; remainder_ = 0; } else { wsState_ = ws00_text_data; dataBegin = begin + 1; remainder_ = 0; } ++begin; break; case ws00_binary_length: remainder_ = remainder_ << 7 | (*begin & 0x7F); if ((*begin & 0x80) == 0) { if (remainder_ == 0 || remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized binary frame of length " << remainder_); return Request::Error; } wsState_ = ws00_binary_data; } ++begin; break; case ws00_text_data: if (static_cast<unsigned char>(*begin) == 0xFF) { state = Request::Complete; wsState_ = ws00_frame_start; dataEnd = begin; } else { ++remainder_; if (remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized text frame of length " << remainder_); return Request::Error; } } ++begin; break; case ws00_binary_data: { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); dataBegin = begin; begin = begin + thisSize; dataEnd = begin; remainder_ -= thisSize; if (remainder_ == 0) { state = Request::Complete; wsState_ = ws00_frame_start; } break; } case ws13_frame_start: { unsigned char frameType = *begin; LOG_DEBUG("ws: new frame, opcode byte=" << (int)frameType); /* RSV1-3 must be 0 */ if (frameType & 0x70) return Request::Error; switch (frameType & 0x0F) { case 0x0: // Continuation frame of a fragmented message if (frameType & 0x80) wsFrameType_ |= 0x80; // mark the end-of-frame break; case 0x1: // Text frame case 0x2: // Binary frame case 0x8: // Close case 0x9: // Ping case 0xA: // Pong wsFrameType_ = frameType; break; default: LOG_ERROR("ws: unknown opcode"); return Request::Error; } wsState_ = ws13_payload_length; wsCount_ = 0; ++begin; break; } case ws13_payload_length: /* Client frame must be masked */ if ((*begin & 0x80) == 0) { LOG_ERROR("ws: client frame not masked"); return Request::Error; } remainder_ = *begin & 0x7F; if (remainder_ < 126) { LOG_DEBUG("ws: new frame length " << remainder_); wsMask_ = 0; wsState_ = ws13_mask; wsCount_ = 4; } else if (remainder_ == 126) { wsState_ = ws13_extended_payload_length; wsCount_ = 2; remainder_ = 0; } else if (remainder_ == 127) { wsState_ = ws13_extended_payload_length; wsCount_ = 8; remainder_ = 0; } ++begin; break; case ws13_extended_payload_length: remainder_ <<= 8; remainder_ |= (unsigned char)(*begin); --wsCount_; if (wsCount_ == 0) { LOG_DEBUG("ws: new frame length " << remainder_); if (remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized frame of length " << remainder_); return Request::Error; } wsMask_ = 0; wsState_ = ws13_mask; wsCount_ = 4; } ++begin; break; case ws13_mask: wsMask_ <<= 8; wsMask_ |= (unsigned char)(*begin); --wsCount_; if (wsCount_ == 0) { LOG_DEBUG("ws: new frame read mask"); if (remainder_ != 0) { wsState_ = ws13_payload; } else { // Frame without data (like pong) if (wsFrameType_ & 0x80) state = Request::Complete; wsState_ = ws13_frame_start; } } ++begin; break; case ws13_payload: { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); dataBegin = begin; begin = begin + thisSize; dataEnd = begin; remainder_ -= thisSize; /* Unmask dataBegin to dataEnd, mask offset in wsCount_ */ for (Buffer::iterator i = dataBegin; i != dataEnd; ++i) { unsigned char d = *i; unsigned char m = (unsigned char)(wsMask_ >> ((3 - wsCount_) * 8)); d = d ^ m; *i = d; wsCount_ = (wsCount_ + 1) % 4; } LOG_DEBUG("ws: reading payload, remains = " << remainder_); if (remainder_ == 0) { if (wsFrameType_ & 0x80) state = Request::Complete; wsState_ = ws13_frame_start; } break; } default: assert(false); } } LOG_DEBUG("ws: " << (dataEnd - dataBegin) << "," << state); if (dataBegin < dataEnd || state == Request::Complete) { if (wsState_ < ws13_frame_start) { if (wsFrameType_ == 0x00) reply->consumeWebSocketMessage(Reply::text_frame, dataBegin, dataEnd, state); } else { Reply::ws_opcode opcode = (Reply::ws_opcode)(wsFrameType_ & 0x0F); reply->consumeWebSocketMessage(opcode, dataBegin, dataEnd, state); } } return state; }
Request::State RequestParser::parseWebSocketMessage(Request& req, ReplyPtr reply, char *& begin, char * end) { switch (wsState_) { case ws_start: { if (req.webSocketVersion != 0 && req.webSocketVersion != 7 && req.webSocketVersion != 8 && req.webSocketVersion != 13) { LOG_ERROR("ws: unsupported protocol version " << req.webSocketVersion); // FIXME add Sec-WebSocket-Version fields return Request::Error; } if (req.webSocketVersion == 0) { LOG_INFO("ws: connect with protocol version 0"); /* * In version 00, the hand shake is two-staged, we first need to * send the 101 to be able to access the part of the handshake * that is sent after the GET */ const Request::Header *host = req.getHeader("Host"); if (!host || host->value.empty()) { LOG_ERROR("ws: missing Host field"); return Request::Error; } wsState_ = ws00_hand_shake; wsCount_ = 0; reply->setStatus(Reply::switching_protocols); reply->addHeader("Connection", "Upgrade"); reply->addHeader("Upgrade", "WebSocket"); const Request::Header *origin = req.getHeader("Origin"); if (origin && !origin->value.empty()) reply->addHeader("Sec-WebSocket-Origin", origin->value.str()); std::string location = std::string(req.urlScheme) + "://" + host->value.str() + req.request_path + "?" + req.request_query; reply->addHeader("Sec-WebSocket-Location", location); reply->consumeData(&*begin, &*begin, Request::Partial); return Request::Complete; } else { LOG_INFO("ws: connect with protocol version " << req.webSocketVersion); std::string accept = doWebSocketHandshake13(req); if (accept.empty()) { LOG_ERROR("ws: error computing handshake result"); return Request::Error; } else { wsState_ = ws13_frame_start; reply->setStatus(Reply::switching_protocols); reply->addHeader("Connection", "Upgrade"); reply->addHeader("Upgrade", "WebSocket"); reply->addHeader("Sec-WebSocket-Accept", accept); #ifdef WTHTTP_WITH_ZLIB std::string compressHeader; if(!doWebSocketPerMessageDeflateNegotiation(req, compressHeader)) return Request::Error; if(!compressHeader.empty()) { // We can use per message deflate if(initInflate()) { LOG_DEBUG("Extension per_message_deflate requested"); reply->addHeader("Sec-WebSocket-Extensions", compressHeader); }else { // Decompress not available disable req.pmdState_.enabled = false; } } #endif reply->consumeData(&*begin, &*begin, Request::Complete); return Request::Complete; } } break; } case ws00_hand_shake: { unsigned thisSize = std::min((::int64_t)(end - begin), (::int64_t)(8 - wsCount_)); memcpy(ws00_buf_ + wsCount_, &*begin, thisSize); wsCount_ += thisSize; begin += thisSize; if (wsCount_ == 8) { bool okay = doWebSocketHandshake00(req); if (okay) { wsState_ = ws00_frame_start; reply->consumeData(ws00_buf_, ws00_buf_ + 16, Request::Complete); return Request::Complete; } else { LOG_ERROR("ws: invalid client hand-shake"); return Request::Error; } } else return Request::Partial; } default: break; } char *dataBegin = begin; char *dataEnd = begin; // Initially assume no data Request::State state = Request::Partial; while (begin < end && state == Request::Partial) { switch (wsState_) { case ws00_frame_start: wsFrameType_ = *begin; if (wsFrameType_ & 0x80) { wsState_ = ws00_binary_length; remainder_ = 0; } else { wsState_ = ws00_text_data; dataBegin = begin + 1; remainder_ = 0; } ++begin; break; case ws00_binary_length: if (remainder_ >= (((int64_t)0x01) << 56)) { LOG_ERROR("ws: oversized binary frame: overflows 64-bit signed integer"); return Request::Error; } remainder_ = remainder_ << 7 | (*begin & 0x7F); if ((*begin & 0x80) == 0) { if (remainder_ == 0 || remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized binary frame of length " << remainder_); return Request::Error; } wsState_ = ws00_binary_data; } ++begin; break; case ws00_text_data: if (static_cast<unsigned char>(*begin) == 0xFF) { state = Request::Complete; wsState_ = ws00_frame_start; dataEnd = begin; } else { ++remainder_; if (remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized text frame of length " << remainder_); return Request::Error; } } ++begin; break; case ws00_binary_data: { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); dataBegin = begin; begin = begin + thisSize; dataEnd = begin; remainder_ -= thisSize; if (remainder_ == 0) { state = Request::Complete; wsState_ = ws00_frame_start; } break; } case ws13_frame_start: { unsigned char frameType = *begin; LOG_DEBUG("ws: new frame, opcode byte=" << (int)frameType); #ifdef WTHTTP_WITH_ZLIB /* RSV1-3 must be 0 */ if (frameType & 0x70 && (!req.pmdState_.enabled && frameType & 0x30)) return Request::Error; frameCompressed_ = frameType & 0x40; #else if(frameType & 0x70) return Request::Error; #endif switch (frameType & 0x0F) { case 0x0: // Continuation frame of a fragmented message if (frameType & 0x80) wsFrameType_ |= 0x80; // mark the end-of-frame break; case 0x1: // Text frame case 0x2: // Binary frame case 0x8: // Close case 0x9: // Ping case 0xA: // Pong wsFrameType_ = frameType; break; default: LOG_ERROR("ws: unknown opcode"); return Request::Error; } wsState_ = ws13_payload_length; wsCount_ = 0; ++begin; break; } case ws13_payload_length: /* Client frame must be masked */ if ((*begin & 0x80) == 0) { LOG_ERROR("ws: client frame not masked"); return Request::Error; } remainder_ = *begin & 0x7F; if (remainder_ < 126) { LOG_DEBUG("ws: new frame length " << remainder_); wsMask_ = 0; wsState_ = ws13_mask; wsCount_ = 4; } else if (remainder_ == 126) { wsState_ = ws13_extended_payload_length; wsCount_ = 2; remainder_ = 0; } else if (remainder_ == 127) { wsState_ = ws13_extended_payload_length; wsCount_ = 8; remainder_ = 0; } ++begin; break; case ws13_extended_payload_length: if (wsCount_ == 8 && (unsigned char)(*begin) > 127) { LOG_ERROR("ws: malformed 8-byte frame length, MSB is not 0"); return Request::Error; } remainder_ <<= 8; remainder_ |= (unsigned char)(*begin); --wsCount_; if (wsCount_ == 0) { LOG_DEBUG("ws: new frame length " << remainder_); if (remainder_ >= MAX_WEBSOCKET_MESSAGE_LENGTH) { LOG_ERROR("ws: oversized frame of length " << remainder_); return Request::Error; } wsMask_ = 0; wsState_ = ws13_mask; wsCount_ = 4; } ++begin; break; case ws13_mask: wsMask_ <<= 8; wsMask_ |= (unsigned char)(*begin); --wsCount_; if (wsCount_ == 0) { LOG_DEBUG("ws: new frame read mask"); if (remainder_ != 0) { wsState_ = ws13_payload; } else { // Frame without data (like pong) if (wsFrameType_ & 0x80) state = Request::Complete; wsState_ = ws13_frame_start; } } ++begin; break; case ws13_payload: { ::int64_t thisSize = std::min((::int64_t)(end - begin), remainder_); dataBegin = begin; begin = begin + thisSize; dataEnd = begin; remainder_ -= thisSize; /* Unmask dataBegin to dataEnd, mask offset in wsCount_ */ for (char *i = dataBegin; i != dataEnd; ++i) { unsigned char d = *i; unsigned char m = (unsigned char)(wsMask_ >> ((3 - wsCount_) * 8)); d = d ^ m; *i = d; wsCount_ = (wsCount_ + 1) % 4; } LOG_DEBUG("ws: reading payload, remains = " << remainder_); if (remainder_ == 0) { if (wsFrameType_ & 0x80) state = Request::Complete; wsState_ = ws13_frame_start; } break; } default: assert(false); } } LOG_DEBUG("ws: " << (dataEnd - dataBegin) << "," << state); if (dataBegin < dataEnd || state == Request::Complete) { char* beg = &*dataBegin; char* end = &*dataEnd; #ifdef WTHTTP_WITH_ZLIB if (frameCompressed_) { Reply::ws_opcode opcode = (Reply::ws_opcode)(wsFrameType_ & 0x0F); if (wsState_ < ws13_frame_start) { if (wsFrameType_ == 0x00) opcode = Reply::text_frame; } unsigned char appendBlock[] = { 0x00, 0x00, 0xff, 0xff }; bool hasMore = false; char buffer[16 * 1024]; do { read_ = 0; bool ret1 = inflate(reinterpret_cast<unsigned char*>(&*beg), end - beg, reinterpret_cast<unsigned char*>(buffer), hasMore); if(!ret1) return Request::Error; reply->consumeWebSocketMessage(opcode, &buffer[0], &buffer[read_], hasMore ? Request::Partial : state); } while (hasMore); if (state == Request::Complete) if(!inflate(appendBlock, 4, reinterpret_cast<unsigned char*>(buffer), hasMore)) return Request::Error; return state; } #endif // handle uncompressed frame if (wsState_ < ws13_frame_start) { if (wsFrameType_ == 0x00) reply->consumeWebSocketMessage(Reply::text_frame, beg, end, state); } else { Reply::ws_opcode opcode = (Reply::ws_opcode)(wsFrameType_ & 0x0F); reply->consumeWebSocketMessage(opcode, beg, end, state); } } return state; }
void Connection::handleReadRequest0() { Buffer& buffer = rcv_buffers_.back(); #ifdef DEBUG try { LOG_DEBUG(socket().native() << "incoming request: " << socket().remote_endpoint().port() << " (avail= " << (rcv_buffer_size_ - (rcv_remaining_ - buffer.data())) << "): " << std::string(rcv_remaining_, std::min((unsigned long)(buffer.data() - rcv_remaining_ + rcv_buffer_size_), (long unsigned)1000))); } catch (...) { } #endif // DEBUG boost::tribool result; boost::tie(result, rcv_remaining_) = request_parser_.parse(request_, rcv_remaining_, buffer.data() + rcv_buffer_size_); if (result) { Reply::status_type status = request_parser_.validate(request_); // FIXME: Let the reply decide whether we're doing websockets, move this logic to WtReply bool doWebSockets = server_->controller()->configuration().webSockets() && (server_->controller()->configuration().sessionPolicy() != Wt::Configuration::DedicatedProcess || server_->configuration().parentPort() != -1); if (doWebSockets) request_.enableWebSocket(); LOG_DEBUG(socket().native() << "request: " << status); if (status >= 300) sendStockReply(status); else { if (request_.webSocketVersion >= 0) { // replace 'http' with 'ws' request_.urlScheme[0] = 'w'; request_.urlScheme[1] = 's'; strncpy(request_.urlScheme + 2, urlScheme() + 4, 7); request_.urlScheme[9] = 0; } else strncpy(request_.urlScheme, urlScheme(), 9); ReplyPtr reply; try { reply = request_handler_.handleRequest (request_, lastWtReply_, lastProxyReply_, lastStaticReply_); reply->setConnection(shared_from_this()); } catch (asio_system_error& e) { LOG_ERROR("Error in handleRequest0(): " << e.what()); handleError(e.code()); return; } rcv_body_buffer_ = false; handleReadBody(reply); } } else if (!result) { sendStockReply(StockReply::bad_request); } else { rcv_buffers_.push_back(Buffer()); startAsyncReadRequest(rcv_buffers_.back(), request_parser_.initialState() ? KEEPALIVE_TIMEOUT : CONNECTION_TIMEOUT); } }