Exemple #1
0
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);
      }
    }
  }
}
Exemple #2
0
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;
  }
}
Exemple #3
0
void Connection::sendStockReply(StockReply::status_type status)
{
  ReplyPtr reply
    (new StockReply(request_, status, "", server_->configuration()));

  reply->setConnection(shared_from_this());
  reply->setCloseConnection();

  startWriteResponse(reply);
}
Exemple #4
0
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;
  }
}
Exemple #5
0
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);
  }
}
Exemple #6
0
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);
  }
}
Exemple #7
0
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);
  }
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}
Exemple #10
0
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);
  }
}