#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#define BUFFER_SIZE 4096
enum CHECK_STATE { CHECK_STATE_REQUESTLINE = 0, CHECK_STATE_HEADER, CHECK_STATE_CONTENT };
enum LINE_STATUS { LINE_OK = 0, LINE_BAD, LINE_OPEN };
enum HTTP_CODE { NO_REQUEST, GET_REQUEST, BAD_REQUEST, FORBIDDEN_REQUEST, INTERNAL_ERROR, CLOSED_CONNECTION };
static const char* szret[] = { "I get a correct result\n", "Something wrong\n" };
LINE_STATUS parse_line( char* buffer, int& checked_index, int& read_index )
{
char temp;
for ( ; checked_index < read_index; ++checked_index )
{
temp = buffer[ checked_index ];
if ( temp == '\r' )
{
if ( ( checked_index + 1 ) == read_index )
{
return LINE_OPEN;
}
else if ( buffer[ checked_index + 1 ] == '\n' )
{
buffer[ checked_index++ ] = '\0';
buffer[ checked_index++ ] = '\0';
return LINE_OK;
}
return LINE_BAD;
}
else if( temp == '\n' )
{
if( ( checked_index > 1 ) && buffer[ checked_index - 1 ] == '\r' )
{
buffer[ checked_index-1 ] = '\0';
buffer[ checked_index++ ] = '\0';
return LINE_OK;
}
return LINE_BAD;
}
}
return LINE_OPEN;
}
HTTP_CODE parse_requestline( char* szTemp, CHECK_STATE& checkstate )
{
char* szURL = strpbrk( szTemp, " \t" );
if ( ! szURL )
{
return BAD_REQUEST;
}
*szURL++ = '\0';
char* szMethod = szTemp;
if ( strcasecmp( szMethod, "GET" ) == 0 )
{
printf( "The request method is GET\n" );
}
else
{
return BAD_REQUEST;
}
szURL += strspn( szURL, " \t" );
char* szVersion = strpbrk( szURL, " \t" );
if ( ! szVersion )
{
return BAD_REQUEST;
}
*szVersion++ = '\0';
szVersion += strspn( szVersion, " \t" );
if ( strcasecmp( szVersion, "HTTP/1.1" ) != 0 )
{
return BAD_REQUEST;
}
if ( strncasecmp( szURL, "http://", 7 ) == 0 )
{
szURL += 7;
szURL = strchr( szURL, '/' );
}
if ( ! szURL || szURL[ 0 ] != '/' )
{
return BAD_REQUEST;
}
//URLDecode( szURL );
printf( "The request URL is: %s\n", szURL );
checkstate = CHECK_STATE_HEADER;
return NO_REQUEST;
}
HTTP_CODE parse_headers( char* szTemp )
{
if ( szTemp[ 0 ] == '\0' )
{
return GET_REQUEST;
}
else if ( strncasecmp( szTemp, "Host:", 5 ) == 0 )
{
szTemp += 5;
szTemp += strspn( szTemp, " \t" );
printf( "the request host is: %s\n", szTemp );
}
else
{
printf( "I can not handle this header\n" );
}
return NO_REQUEST;
}
HTTP_CODE parse_content( char* buffer, int& checked_index, CHECK_STATE& checkstate, int& read_index, int& start_line )
{
LINE_STATUS linestatus = LINE_OK;
HTTP_CODE retcode = NO_REQUEST;
while( ( linestatus = <span style="font-size:24px;color:#FF0000;">parse_line</span>( buffer, checked_index, read_index ) ) == LINE_OK )//解析出一行的内容
{
char* szTemp = buffer + start_line;
start_line = checked_index;
switch ( checkstate )
{
case CHECK_STATE_REQUESTLINE:
{
retcode = <span style="font-size:24px;color:#FF0000;">parse_requestline</span>( temp, checkstate );//分析请求行
if ( retcode == BAD_REQUEST )
{
return BAD_REQUEST;
}
break;
}
case CHECK_STATE_HEADER:
{
retcode = <span style="font-size:24px;color:#FF0000;">parse_headers</span>( temp );//分析头部字段
if ( retcode == BAD_REQUEST )
{
return BAD_REQUEST;
}
else if ( retcode == GET_REQUEST )
{
return GET_REQUEST;
}
break;
}
default:
{
return INTERNAL_ERROR;
}
}
}
if( linestatus == LINE_OPEN )
{
return NO_REQUEST;
}
else
{
return BAD_REQUEST;
}
}
int main( int argc, char* argv[] )
{
if( argc <= 2 )
{
printf( "usage: %s ip_address port_number\n", basename( argv[0] ) );
return 1;
}
const char* ip = argv[1];
int port = atoi( argv[2] );
struct sockaddr_in address;
bzero( &address, sizeof( address ) );
address.sin_family = AF_INET;
inet_pton( AF_INET, ip, &address.sin_addr );
address.sin_port = htons( port );
int listenfd = socket( PF_INET, SOCK_STREAM, 0 );
assert( listenfd >= 0 );
int ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) );
assert( ret != -1 );
ret = listen( listenfd, 5 );
assert( ret != -1 );
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof( client_address );
int fd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength );
if( fd < 0 )
{
printf( "errno is: %d\n", errno );
}
else
{
char buffer[ BUFFER_SIZE ];
memset( buffer, '\0', BUFFER_SIZE );
int data_read = 0;
int read_index = 0;
int checked_index = 0;
int start_line = 0;
CHECK_STATE checkstate = CHECK_STATE_REQUESTLINE;
while( 1 )
{
data_read = recv( fd, buffer + read_index, BUFFER_SIZE - read_index, 0 );
if ( data_read == -1 )
{
printf( "reading failed\n" );
break;
}
else if ( data_read == 0 )
{
printf( "remote client has closed the connection\n" );
break;
}
read_index += data_read;
//分析目前已经获得的所有客户数据
//buffer表示缓冲区,checked_index表示当前已分析多少字节的客户数据,cheeckstate主状态机的初始状态,read_index表示buffer中已读字节数,start_line表示当前分析到哪一行
HTTP_CODE result = <span style="font-size:24px;color:#FF0000;">parse_content</span>( buffer, checked_index, checkstate, read_index, start_line );
if( result == NO_REQUEST )
{
continue;
}
else if( result == GET_REQUEST )
{
send( fd, szret[0], strlen( szret[0] ), 0 );
break;
}
else
{
send( fd, szret[1], strlen( szret[1] ), 0 );
break;
}
}
close( fd );
}
close( listenfd );
return 0;
}
</span>
Linux high performance:http请求的读取和分析
最新推荐文章于 2023-03-19 19:55:00 发布