高性能服务编程:有限状态机解析HTTP请求代码

 

 

相关函数:

//该函数返回str1中第一个匹配字符串str2的字符数,未找到返回null。
char *strpbrk(const char *str1, const char *str2)

 

/*
若参数s1 和s2 字符串相同则返回0。s1 长度大于s2 长度则返回大于0 的值,s1 长度若小于s2 长度则返回小于0 的值。
*/

int strcasecmp (const char *s1, const char *s2);

 

/*
返回字符串 str 开头连续包含字符串 accept 内的字符数目。所以,如果 str 所包含的字符都属于 accept,那么返回 str 的长度;如果 str 的第一个字符不属于 accept,那么返回 0。
*/

size_t strspn(const char *str, const char * accept);

 

//该函数返回在字符串 str 中第一次出现字符 c 的位置,如果未找到该字符则返回 NULL。

char *strchr(const char *str, int c)

 

 

  1 #include <sys/socket.h>
  2 #include <netinet/in.h>
  3 #include <arpa/inet.h>
  4 #include <assert.h>
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <unistd.h>
  8 #include <errno.h>
  9 #include <string.h>
 10 #include <fcntl.h>
 11 
 12 #define BUFFER_SIZE 4096
 13 enum CHECK_STATE { CHECK_STATE_REQUESTLINE = 0, CHECK_STATE_HEADER, CHECK_STATE_CONTENT };
 14 enum LINE_STATUS { LINE_OK = 0, LINE_BAD, LINE_OPEN };
 15 enum HTTP_CODE { NO_REQUEST, GET_REQUEST, BAD_REQUEST, FORBIDDEN_REQUEST, INTERNAL_ERROR, CLOSED_CONNECTION };
 16 static const char* szret[] = { "I get a correct result\n", "Something wrong\n" };
 17 
 18 LINE_STATUS parse_line( char* buffer, int& checked_index, int& read_index )
 19 {
 20     char temp;
 21     for ( ; checked_index < read_index; ++checked_index )
 22     {
 23         temp = buffer[ checked_index ];
 24         if ( temp == \r )
 25         {
 26             if ( ( checked_index + 1 ) == read_index )
 27             {
 28                 return LINE_OPEN;
 29             }
 30             else if ( buffer[ checked_index + 1 ] == \n )
 31             {
 32                 buffer[ checked_index++ ] = \0;
 33                 buffer[ checked_index++ ] = \0;
 34                 return LINE_OK;
 35             }
 36             return LINE_BAD;
 37         }
 38         else if( temp == \n )
 39         {
 40             if( ( checked_index > 1 ) &&  buffer[ checked_index - 1 ] == \r )
 41             {
 42                 buffer[ checked_index-1 ] = \0;
 43                 buffer[ checked_index++ ] = \0;
 44                 return LINE_OK;
 45             }
 46             return LINE_BAD;
 47         }
 48     }
 49     return LINE_OPEN;
 50 }
 51 
 52 HTTP_CODE parse_requestline( char* szTemp, CHECK_STATE& checkstate )
 53 {
 54     char* szURL = strpbrk( szTemp, " \t" );
 55     if ( ! szURL )
 56     {
 57         return BAD_REQUEST;
 58     }
 59     *szURL++ = \0;
 60 
 61     char* szMethod = szTemp;
 62     if ( strcasecmp( szMethod, "GET" ) == 0 )
 63     {
 64         printf( "The request method is GET\n" );
 65     }
 66     else
 67     {
 68         return BAD_REQUEST;
 69     }
 70 
 71     szURL += strspn( szURL, " \t" );
 72     char* szVersion = strpbrk( szURL, " \t" );
 73     if ( ! szVersion )
 74     {
 75         return BAD_REQUEST;
 76     }
 77     *szVersion++ = \0;
 78     szVersion += strspn( szVersion, " \t" );
 79     if ( strcasecmp( szVersion, "HTTP/1.1" ) != 0 )
 80     {
 81         return BAD_REQUEST;
 82     }
 83 
 84     if ( strncasecmp( szURL, "http://", 7 ) == 0 )
 85     {
 86         szURL += 7;
 87         szURL = strchr( szURL, / );
 88     }
 89 
 90     if ( ! szURL || szURL[ 0 ] != / )
 91     {
 92         return BAD_REQUEST;
 93     }
 94 
 95     //URLDecode( szURL );
 96     printf( "The request URL is: %s\n", szURL );
 97     checkstate = CHECK_STATE_HEADER;
 98     return NO_REQUEST;
 99 }
100 
101 HTTP_CODE parse_headers( char* szTemp )
102 {
103     if ( szTemp[ 0 ] == \0 )
104     {
105         return GET_REQUEST;
106     }
107     else if ( strncasecmp( szTemp, "Host:", 5 ) == 0 )
108     {
109         szTemp += 5;
110         szTemp += strspn( szTemp, " \t" );
111         printf( "the request host is: %s\n", szTemp );
112     }
113     else
114     {
115         printf( "I can not handle this header\n" );
116     }
117 
118     return NO_REQUEST;
119 }
120 
121 HTTP_CODE parse_content( char* buffer, int& checked_index, CHECK_STATE& checkstate, int& read_index, int& start_line )
122 {
123     LINE_STATUS linestatus = LINE_OK;
124     HTTP_CODE retcode = NO_REQUEST;
125     while( ( linestatus = parse_line( buffer, checked_index, read_index ) ) == LINE_OK )
126     {
127         char* szTemp = buffer + start_line;
128         start_line = checked_index;
129         switch ( checkstate )
130         {
131             case CHECK_STATE_REQUESTLINE:
132             {
133                 retcode = parse_requestline( szTemp, checkstate );
134                 if ( retcode == BAD_REQUEST )
135                 {
136                     return BAD_REQUEST;
137                 }
138                 break;
139             }
140             case CHECK_STATE_HEADER:
141             {
142                 retcode = parse_headers( szTemp );
143                 if ( retcode == BAD_REQUEST )
144                 {
145                     return BAD_REQUEST;
146                 }
147                 else if ( retcode == GET_REQUEST )
148                 {
149                     return GET_REQUEST;
150                 }
151                 break;
152             }
153             default:
154             {
155                 return INTERNAL_ERROR;
156             }
157         }
158     }
159     if( linestatus == LINE_OPEN )
160     {
161         return NO_REQUEST;
162     }
163     else
164     {
165         return BAD_REQUEST;
166     }
167 }
168 
169 int main( int argc, char* argv[] )
170 {
171     if( argc <= 2 )
172     {
173         printf( "usage: %s ip_address port_number\n", basename( argv[0] ) );
174         return 1;
175     }
176     const char* ip = argv[1];
177     int port = atoi( argv[2] );
178     
179     struct sockaddr_in address;
180     bzero( &address, sizeof( address ) );
181     address.sin_family = AF_INET;
182     inet_pton( AF_INET, ip, &address.sin_addr );
183     address.sin_port = htons( port );
184     
185     int listenfd = socket( PF_INET, SOCK_STREAM, 0 );
186     assert( listenfd >= 0 );
187     
188     int ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) );
189     assert( ret != -1 );
190     
191     ret = listen( listenfd, 5 );
192     assert( ret != -1 );
193     
194     struct sockaddr_in client_address;
195     socklen_t client_addrlength = sizeof( client_address );
196     int fd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength );
197     if( fd < 0 )
198     {
199         printf( "errno is: %d\n", errno );
200     }
201     else
202     {
203         char buffer[ BUFFER_SIZE ];
204         memset( buffer, \0, BUFFER_SIZE );
205         int data_read = 0;
206         int read_index = 0;
207         int checked_index = 0;
208         int start_line = 0;
209         CHECK_STATE checkstate = CHECK_STATE_REQUESTLINE;
210         while( 1 )
211         {
212             data_read = recv( fd, buffer + read_index, BUFFER_SIZE - read_index, 0 );
213             if ( data_read == -1 )
214             {
215                 printf( "reading failed\n" );
216                 break;
217             }
218             else if ( data_read == 0 )
219             {
220                 printf( "remote client has closed the connection\n" );
221                 break;
222             }
223     
224             read_index += data_read;
225             HTTP_CODE result = parse_content( buffer, checked_index, checkstate, read_index, start_line );
226             if( result == NO_REQUEST )
227             {
228                 continue;
229             }
230             else if( result == GET_REQUEST )
231             {
232                 send( fd, szret[0], strlen( szret[0] ), 0 );
233                 break;
234             }
235             else
236             {
237                 send( fd, szret[1], strlen( szret[1] ), 0 );
238                 break;
239             }
240         }
241         close( fd );
242     }
243     
244     close( listenfd );
245     return 0;
246 }

 

高性能服务编程:有限状态机解析HTTP请求代码

上一篇:续上节,,基于App布局信息操作手机


下一篇:移动端h5不支持font-family里面的楷体、微软雅黑等字体