⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httprequestparser.cpp

📁 用c++编写http server的源码库,对socket等网络处理的代码可迅速转为己用.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// -----------------------------------------------------------------// libpion: a C++ framework for building lightweight HTTP interfaces// -----------------------------------------------------------------// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)//// Distributed under the Boost Software License, Version 1.0.// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt//#include <libpion/HTTPRequestParser.hpp>#include <boost/bind.hpp>#include <boost/asio.hpp>namespace pion {	// begin namespace pion	// static members of HTTPRequestParserconst unsigned int	HTTPRequestParser::METHOD_MAX = 1024;	// 1 KBconst unsigned int	HTTPRequestParser::RESOURCE_MAX = 256 * 1024;	// 256 KBconst unsigned int	HTTPRequestParser::QUERY_STRING_MAX = 1024 * 1024;	// 1 MBconst unsigned int	HTTPRequestParser::HEADER_NAME_MAX = 1024;	// 1 KBconst unsigned int	HTTPRequestParser::HEADER_VALUE_MAX = 1024 * 1024;	// 1 MBconst unsigned int	HTTPRequestParser::QUERY_NAME_MAX = 1024;	// 1 KBconst unsigned int	HTTPRequestParser::QUERY_VALUE_MAX = 1024 * 1024;	// 1 MBconst unsigned int	HTTPRequestParser::COOKIE_NAME_MAX = 1024;	// 1 KBconst unsigned int	HTTPRequestParser::COOKIE_VALUE_MAX = 1024 * 1024;	// 1 MBconst unsigned int	HTTPRequestParser::POST_CONTENT_MAX = 1024 * 1024;	// 1 MB		// HTTPRequestParser member functionsvoid HTTPRequestParser::readRequest(void){	if (m_tcp_conn->getSSLFlag()) {#ifdef PION_HAVE_SSL		m_tcp_conn->getSSLSocket().async_read_some(boost::asio::buffer(m_read_buffer),												   boost::bind(&HTTPRequestParser::readHeaderBytes,															   shared_from_this(),															   boost::asio::placeholders::error,															   boost::asio::placeholders::bytes_transferred));#else		PION_LOG_ERROR(m_logger, "SSL flag set for server, but support is not enabled");		m_tcp_conn->finish();#endif			} else {		m_tcp_conn->getSocket().async_read_some(boost::asio::buffer(m_read_buffer),												boost::bind(&HTTPRequestParser::readHeaderBytes,															shared_from_this(),															boost::asio::placeholders::error,															boost::asio::placeholders::bytes_transferred));	}}void HTTPRequestParser::readHeaderBytes(const boost::system::error_code& read_error,										std::size_t bytes_read){	if (read_error) {		// a read error occured		handleReadError(read_error);		return;	}	PION_LOG_DEBUG(m_logger, "Read " << bytes_read << " bytes from HTTP request");		// parse the bytes read from the last operation	const char *read_ptr = m_read_buffer.data();	const char * const read_end = read_ptr + bytes_read;	boost::tribool result = parseRequestHeaders(read_ptr, bytes_read);	PION_LOG_DEBUG(m_logger, "Parsed " << (read_ptr - m_read_buffer.data()) << " HTTP header bytes");	if (result) {		// finished reading request headers and they are valid		// check if we have post content to read		const unsigned long content_length =			m_http_request->hasHeader(HTTPTypes::HEADER_CONTENT_LENGTH)			? strtoul(m_http_request->getHeader(HTTPTypes::HEADER_CONTENT_LENGTH).c_str(), 0, 10)			: 0;		if (content_length == 0) {						// there is no post content to read			readContentBytes(read_error, 0);					} else {			// read the post content			unsigned long content_bytes_to_read = content_length;			m_http_request->setContentLength(content_length);			char *post_buffer = m_http_request->createPostContentBuffer();						if (read_ptr < read_end) {				// there are extra bytes left from the last read operation				// copy them into the beginning of the content buffer				const unsigned int bytes_left_in_read_buffer = read_end - read_ptr;								if (bytes_left_in_read_buffer >= content_length) {					// the last read operation included all of the post content					memcpy(post_buffer, read_ptr, content_length);					content_bytes_to_read = 0;					PION_LOG_DEBUG(m_logger, "Parsed " << content_length << " request content bytes from last read operation (finished)");				} else {					// only some of the post content has been read so far					memcpy(post_buffer, read_ptr, bytes_left_in_read_buffer);					content_bytes_to_read -= bytes_left_in_read_buffer;					post_buffer += bytes_left_in_read_buffer;					PION_LOG_DEBUG(m_logger, "Parsed " << bytes_left_in_read_buffer << " request content bytes from last read operation (partial)");				}			}			if (content_bytes_to_read == 0) {							// read all of the content from the last read operation				readContentBytes(read_error, 0);			} else {				// read the rest of the post content into the buffer				// and only return after we've finished or an error occurs				if (m_tcp_conn->getSSLFlag()) {#ifdef PION_HAVE_SSL					boost::asio::async_read(m_tcp_conn->getSSLSocket(),											boost::asio::buffer(post_buffer, content_bytes_to_read),											boost::asio::transfer_at_least(content_bytes_to_read),											boost::bind(&HTTPRequestParser::readContentBytes,														shared_from_this(),														boost::asio::placeholders::error,														boost::asio::placeholders::bytes_transferred));#else					PION_LOG_ERROR(m_logger, "SSL flag set for server, but support is not enabled");					m_tcp_conn->finish();#endif				} else {					boost::asio::async_read(m_tcp_conn->getSocket(),											boost::asio::buffer(post_buffer, content_bytes_to_read),											boost::asio::transfer_at_least(content_bytes_to_read),											boost::bind(&HTTPRequestParser::readContentBytes,														shared_from_this(),														boost::asio::placeholders::error,														boost::asio::placeholders::bytes_transferred));				}			}		}			} else if (!result) {		// the request is invalid or an error occured	#ifndef NDEBUG		// display extra error information if debug mode is enabled		std::string bad_request;		read_ptr = m_read_buffer.data();		while (read_ptr < read_end && bad_request.size() < 50) {			if (!isprint(*read_ptr) || *read_ptr == '\n' || *read_ptr=='\r')				bad_request += '.';			else bad_request += *read_ptr;			++read_ptr;		}		PION_LOG_ERROR(m_logger, "Bad request debug: " << bad_request);	#endif		m_http_request->setIsValid(false);		m_request_handler(m_http_request, m_tcp_conn);			} else {		// not yet finished parsing the request -> read more data				readRequest();	}}void HTTPRequestParser::readContentBytes(const boost::system::error_code& read_error,										 std::size_t bytes_read){	if (read_error) {		// a read error occured		handleReadError(read_error);		return;	}	if (bytes_read != 0) {		PION_LOG_DEBUG(m_logger, "Read " << bytes_read << " request content bytes (finished)");	}	// the request is valid	m_http_request->setIsValid(true);		// parse query pairs from the URI query string	if (! m_http_request->getQueryString().empty()) {		if (! parseURLEncoded(m_http_request->getQueryParams(),							  m_http_request->getQueryString().c_str(),							  m_http_request->getQueryString().size())) 			PION_LOG_WARN(m_logger, "Request query string parsing failed (URI)");	}		// parse query pairs from post content (x-www-form-urlencoded)	if (m_http_request->getHeader(HTTPTypes::HEADER_CONTENT_TYPE) ==		HTTPTypes::CONTENT_TYPE_URLENCODED)	{		if (! parseURLEncoded(m_http_request->getQueryParams(),							  m_http_request->getPostContent(),							  m_http_request->getContentLength())) 			PION_LOG_WARN(m_logger, "Request query string parsing failed (POST content)");	}		// parse "Cookie" headers	std::pair<HTTPTypes::Headers::const_iterator, HTTPTypes::Headers::const_iterator>		cookie_pair = m_http_request->getHeaders().equal_range(HTTPTypes::HEADER_COOKIE);	for (HTTPTypes::Headers::const_iterator cookie_iterator = cookie_pair.first;		 cookie_iterator != m_http_request->getCookieParams().end()		 && cookie_iterator != cookie_pair.second; ++cookie_iterator)	{		if (! parseCookieHeader(m_http_request->getCookieParams(),								cookie_iterator->second) )			PION_LOG_WARN(m_logger, "Cookie header parsing failed");	}		// call the request handler with the finished request	m_request_handler(m_http_request, m_tcp_conn);}void HTTPRequestParser::handleReadError(const boost::system::error_code& read_error){	// only log errors if the parsing has already begun	if (m_parse_state != PARSE_METHOD_START) {		if (read_error == boost::asio::error::operation_aborted) {			// if the operation was aborted, the acceptor was stopped,			// which means another thread is shutting-down the server			PION_LOG_INFO(m_logger, "HTTP request parsing aborted (shutting down)");		} else {			PION_LOG_INFO(m_logger, "HTTP request parsing aborted (" << read_error.message() << ')');		}	}	// close the connection, forcing the client to establish a new one	m_tcp_conn->finish();}boost::tribool HTTPRequestParser::parseRequestHeaders(const char *& ptr,													  const size_t len){	// parse characters available in the read buffer	const char * const end = ptr + len;		while (ptr < end) {		switch (m_parse_state) {		case PARSE_METHOD_START:			// we have not yet started parsing the HTTP method string			if (*ptr != ' ' && *ptr!='\r' && *ptr!='\n') {	// ignore leading whitespace				if (!isChar(*ptr) || isControl(*ptr) || isSpecial(*ptr))					return false;				m_parse_state = PARSE_METHOD;				m_method.erase();				m_method.push_back(*ptr);			}			break;		case PARSE_METHOD:			// we have started parsing the HTTP method string			if (*ptr == ' ') {				m_http_request->setMethod(m_method);				m_resource.erase();				m_parse_state = PARSE_URI_STEM;			} else if (!isChar(*ptr) || isControl(*ptr) || isSpecial(*ptr)) {				return false;			} else if (m_method.size() >= METHOD_MAX) {				return false;			} else {				m_method.push_back(*ptr);			}			break;		case PARSE_URI_STEM:			// we have started parsing the URI stem (or resource name)			if (*ptr == ' ') {				m_http_request->setResource(m_resource);				m_parse_state = PARSE_HTTP_VERSION_H;			} else if (*ptr == '?') {				m_http_request->setResource(m_resource);				m_query_string.erase();				m_parse_state = PARSE_URI_QUERY;			} else if (isControl(*ptr)) {				return false;			} else if (m_resource.size() >= RESOURCE_MAX) {				return false;			} else {				m_resource.push_back(*ptr);			}			break;		case PARSE_URI_QUERY:			// we have started parsing the URI query string			if (*ptr == ' ') {				m_http_request->setQueryString(m_query_string);				m_parse_state = PARSE_HTTP_VERSION_H;			} else if (isControl(*ptr)) {				return false;			} else if (m_query_string.size() >= QUERY_STRING_MAX) {				return false;			} else {				m_query_string.push_back(*ptr);			}			break;					case PARSE_HTTP_VERSION_H:			// parsing "HTTP"			if (*ptr != 'H') return false;			m_parse_state = PARSE_HTTP_VERSION_T_1;			break;		case PARSE_HTTP_VERSION_T_1:			// parsing "HTTP"			if (*ptr != 'T') return false;			m_parse_state = PARSE_HTTP_VERSION_T_2;			break;		case PARSE_HTTP_VERSION_T_2:			// parsing "HTTP"			if (*ptr != 'T') return false;			m_parse_state = PARSE_HTTP_VERSION_P;			break;		case PARSE_HTTP_VERSION_P:			// parsing "HTTP"			if (*ptr != 'P') return false;			m_parse_state = PARSE_HTTP_VERSION_SLASH;			break;		case PARSE_HTTP_VERSION_SLASH:			// parsing slash after "HTTP"			if (*ptr != '/') return false;			m_parse_state = PARSE_HTTP_VERSION_MAJOR_START;			break;		case PARSE_HTTP_VERSION_MAJOR_START:			// parsing the first digit of the major version number			if (!isDigit(*ptr)) return false;			m_http_request->setVersionMajor(*ptr - '0');			m_parse_state = PARSE_HTTP_VERSION_MAJOR;			break;		case PARSE_HTTP_VERSION_MAJOR:			// parsing the major version number (not first digit)			if (*ptr == '.') {				m_parse_state = PARSE_HTTP_VERSION_MINOR_START;			} else if (isDigit(*ptr)) {				m_http_request->setVersionMajor( (m_http_request->getVersionMajor() * 10)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -