예제 #1
0
void http_server::on_connection(tcp_socket& socket)
{
    http_request* request = new http_request(socket);
    request->connect_on_headers_end([this](http_request& request, http_response& response){
        on_request(request, response);
    });
    request->connect_on_body([this](http_request& request, const std::string& data, http_response& response){
        if (data != "")
        {
            on_body(request, data, response, *this);
        }
    });
    requests_.push_back(std::unique_ptr<http_request>(request));
}
예제 #2
0
/*  Called repeatedly for the content body. The passed buffer
    has already had the transfer-encoding removed.
*/
int
basic_parser::do_body (char const* in, std::size_t bytes)
{
    on_body (in, bytes);
    return 0;
}
예제 #3
0
파일: http.cpp 프로젝트: PKRoma/hellepoll
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");
		}
	}
}