Example #1
0
void Transport_parser::parse(const char* data, size_t len)
{
  if(transport_ != nullptr)
  {
    transport_->load_cargo(data, len);
  }
  else
  {
    transport_ = std::make_unique<Transport>(Header::parse(data));
    
    if(on_header)
      on_header(transport_->header());

    len -= sizeof(Header);

    transport_->load_cargo(data + sizeof(Header), len);
  }

  if(transport_->is_complete())
    on_complete(std::move(transport_));
}
Example #2
0
void HttpServerConnection::read() {
	while(!is_closed()) {
		switch(read_state) {
		case LINE:
			// get the request line
			try {
				if(!async_read_in(line,sizeof(uri)-1))
					return;
			} catch(EndOfStreamError*) {
				if(!count)
					throw;
				// so we get end-of-stream when keep-alive?  no problem
				return;
			}
			if(!line.ends_with("\r\n",2))
				HttpError::Throw(HttpError::ERequestURITooLong,*this);
			if(!memcmp(line.cstr(),"\r\n",3)) { // empty lines are ok before request line
				line.clear();
				continue;
			}
			count++;
			read_state = HEADER;
			{
				const char* method = strtok(line.cstr()," ");
				strncpy(uri,strtok(NULL," \r"),sizeof(this->uri));
				const char* v = strtok(NULL,"\r");
				if(!memcmp(v,"HTTP/1.1",9))
					version = HTTP_1_1;
				else if(!memcmp(v,"HTTP/1.0",9))
					version = HTTP_1_0;
				else
					version = HTTP_0_9;
				in_encoding_chunked = false;
				in_content_length = -1; // not known
				keep_alive = out_encoding_chunked = (HTTP_1_1 == version);
				on_request(method,uri);
			}
			line.clear();
			break;
		case HEADER:
			if(!async_read_in(line))
				return;
			if(!memcmp("\r\n",line.cstr(),3)) {
				read_state = BODY;
				if(keep_alive && !in_encoding_chunked && (-1 == in_content_length))
					in_content_length = 0; // length isn't specified, yet its keep-alive, so there is no content
				line.clear();
				on_body();
				break;
			}
			if(!line.ends_with("\r\n",2))
				HttpError::Throw(HttpError::ERequestEntityTooLarge,*this);
			{
				const char* header = strtok(line.cstr()," "), *value = strtok(NULL,"\r");
				if(!ends_with(header,":",1))
					HttpError::Throw(HttpError::EBadRequest,*this);
				if((write_state == LINE) && !strcasecmp(header,"connection:") && !strcasecmp(value,"keep-alive"))
					keep_alive = true;
				else if(!strcasecmp(header,"content-length:")) {
					in_content_length = atoi(value);
					if(in_content_length < 0)
						HttpError::Throw(HttpError::EBadRequest,*this);
				} else if(!strcasecmp(header,"transfer-encoding:"))
					in_encoding_chunked = !strcasecmp(value,"chunked");
				on_header(header,value);
			}
			line.clear();
			break;
		case BODY:
			if(in_encoding_chunked) { //RFC2616-s4.4 says this overrides any explicit content-length header
				ThrowInternalError("in encoding chunked not implemented yet");
			} else if(!keep_alive && (-1 == in_content_length)) {
				// read all available
				uint8_t* chunk;
				while(uint16_t len = async_read_buffered(chunk))
					on_data(chunk,len);
			} else if(-1 != in_content_length) {
				// read all available
				while(in_content_length) {
					uint8_t* chunk;
					if(const uint16_t len = async_read_buffered(chunk,in_content_length)) {
						in_content_length -= len;
						on_data(chunk,len);
					} else
						return;
				}
				if(!keep_alive) {
					read_state = FINISHED;
					shutdown(fd,SHUT_RD);
					return;
				}
				read_state = LINE;
			} else
				ThrowInternalError("cannot cope with combination of keep_alive %d, content_length %d and encoding_chunked %d",
					keep_alive,in_content_length,in_encoding_chunked);
			break;
		default:
			ThrowInternalError("unexpected read_state");
		}
	}
}