|
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <assert.h>
- #include <ctype.h>
-
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <errno.h>
-
- #include "http_parser.h"
-
- #include "dynamic_buffer.h"
- #include "http_response.h"
- #include "util.h"
-
- #include "cJSON.h"
-
- #define SERVER_STRING "Server: tinyhttpserver/0.1.0\r\n"
-
- int OnMessageBegin(http_parser *o)
- {
- (void)o;
- printf("\n***MESSAGE BEGIN***\n\n");
- return 0;
- }
-
- int OnHeadersComplete(http_parser *o)
- {
- (void)o;
- printf("\n***HEADERS COMPLETE***\n\n");
- return 0;
- }
-
- int OnMessageComplete(http_parser *o)
- {
- (void)o;
- printf("\n***MESSAGE COMPLETE***\n\n");
- return 0;
- }
-
- int OnUrl(http_parser* o, const char* at, size_t length)
- {
- (void)o;
- printf("Url: %.*s\n", (int)length, at);
- return 0;
- }
-
- int OnHeaderField(http_parser* o, const char* at, size_t length)
- {
- (void)o;
- printf("Header field: %.*s\n", (int)length, at);
- return 0;
- }
-
- int OnHeaderValue(http_parser* o, const char* at, size_t length)
- {
- (void)o;
- printf("Header value: %.*s\n", (int)length, at);
- return 0;
- }
-
- int OnBody(http_parser* o, const char* at, size_t length)
- {
- (void)o;
- cJSON *json = cJSON_ParseWithLength(at, length);
- if (json == NULL)
- {
- char *dst = (char *)malloc(length * 2);
- printf("Body Other: %.*s\n", (int)length, at);
- if (HttpUrlEncodeWithLength(at, length, dst, length * 2) > 0)
- {
- printf("Body Other Encoded: %s\n", dst);
- }
- free(dst);
- }
- else
- {
- char *json_str = cJSON_Print(json);
- printf("Body JSON: %s\n", json_str);
- cJSON_free(json_str);
- cJSON_Delete(json);
- }
-
- return 0;
- }
-
- void *ParseRequest(void *arg);
-
- static void ReceiveAndParseRequestHeader(int sockfd, DynamicBuffer *cache)
- {
- int end_of_header = 0;
-
- uint8_t* p = NULL;
- uint8_t* q = NULL;
- size_t state = 0;
-
- ssize_t receive_size;
-
- DynamicBuffer_Clear(cache);
-
- while (!end_of_header)
- {
- receive_size = recv(sockfd, DynamicBuffer_AvailableBuffer(cache), DynamicBuffer_AvailableCapacity(cache) - 1, 0);
-
- if (receive_size > 0)
- {
- p = DynamicBuffer_AvailableBuffer(cache);
- DynamicBuffer_Resize(cache, DynamicBuffer_Size(cache) + receive_size);
-
- /// Small state machine to judge whether reach to the end of response header.
- for (q = p + receive_size; p < q; p++)
- {
- if (*p == '\r' && (state == 0 || state == 2))
- {
- state++;
- }
- else if (*p == '\n' && (state == 1 || state == 3))
- {
- state++;
- }
- else
- {
- state = 0;
- }
-
- if (state == 4)
- {
- p++;
- break;
- }
- }
-
- if (state == 4)
- {
- end_of_header = 1;
- }
- else
- {
- /// The buffer is not enough
- DynamicBuffer_Reserve(cache, DynamicBuffer_Capacity(cache) + receive_size);
- }
- }
- else
- {
- printf("[E] recv error!\n");
- break;
- }
- }
-
- if (end_of_header)
- {
- /// Dump the received data
- // printf("%.*s\n", (int)DynamicBuffer_Size(cache), (char *)DynamicBuffer_BufferAt(cache, 0));
- /// Pop all the header data
- // DynamicBuffer_ResetBuffer(cache, (size_t)(p - (uint8_t *)DynamicBuffer_Buffer(cache)));
- ParseRequest(cache);
- }
- else /// Some errors occurred
- {
- DynamicBuffer_Clear(cache);
- }
- }
-
- void *ParseRequest(void *arg)
- {
- DynamicBuffer *db = (DynamicBuffer *)arg;
-
- http_parser_settings settings;
-
- memset(&settings, 0, sizeof(settings));
-
- settings.on_message_begin = OnMessageBegin;
- settings.on_url = OnUrl;
- settings.on_header_field = OnHeaderField;
- settings.on_header_value = OnHeaderValue;
- settings.on_headers_complete = OnHeadersComplete;
- settings.on_body = OnBody;
- settings.on_message_complete = OnMessageComplete;
-
- http_parser parser;
- http_parser_init(&parser, HTTP_REQUEST);
-
- size_t nparsed = http_parser_execute(&parser, &settings, (char *)DynamicBuffer_Buffer(db), DynamicBuffer_Size(db));
-
- if (nparsed != (size_t)DynamicBuffer_Size(db))
- {
- fprintf(stderr,
- "Error: %s (%s)\n",
- http_errno_description(HTTP_PARSER_ERRNO(&parser)),
- http_errno_name(HTTP_PARSER_ERRNO(&parser)));
- return NULL;
- }
-
- return NULL;
- }
-
- int TinyHttpServerStartup(const char *host, uint16_t *port)
- {
- int httpd = 0;
- struct sockaddr_in server_addr;
-
- httpd = socket(AF_INET, SOCK_STREAM, 0);
- if (httpd == -1)
- {
- printf("[E] Failed to create server socket\n");
- exit(EXIT_FAILURE);
- }
-
- // bzero(&server_addr, sizeof(server_addr));
- memset(&server_addr, 0, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(*port);
- server_addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(httpd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("[E] Failed to bind server socket on %s:%d\n", host, *port);
- exit(EXIT_FAILURE);
- }
-
- // If dynamically allocating a port
- if (*port == 0)
- {
- socklen_t namelen = sizeof(server_addr);
- if (getsockname(httpd, (struct sockaddr *)&server_addr, &namelen) == -1)
- {
- printf("[E] Failed to getsockname\n");
- exit(EXIT_FAILURE);
- }
- *port = ntohs(server_addr.sin_port);
- }
-
- if (listen(httpd, 5) < 0)
- {
- printf("[E] Failed to bind server socket on %s:%d\n", host, *port);
- exit(EXIT_FAILURE);
- }
-
- return httpd;
- }
-
- void TinyHttpServerRun(const char *host, uint16_t port)
- {
- int server_sock_fd = -1;
- int client_sock_fd = -1;
- struct sockaddr_in client_name;
-
- socklen_t client_name_len = sizeof(client_name);
- pthread_t new_client_thread;
-
- DynamicBuffer cache;
- DynamicBuffer_Construct(&cache);
-
- DynamicBuffer output;
- DynamicBuffer_Construct(&output);
-
- HttpResponseHeader response_header;
- HttpResponseHeader_Construct(&response_header);
-
- DynamicBuffer_AppendString(&output, "{\"code\": 0, \"msg\": \"OK\"}");
-
- server_sock_fd = TinyHttpServerStartup(host, &port);
-
- printf("TinyHttpServer running on %s:%d\n", host, port);
-
- while (1)
- {
- client_sock_fd = accept(server_sock_fd, (struct sockaddr *)&client_name, &client_name_len);
-
- if (client_sock_fd == -1)
- {
- printf("[E] Failed to accept a new client socket!\n");
- exit(EXIT_FAILURE);
- }
-
- ReceiveAndParseRequestHeader(client_sock_fd, &cache);
-
- HttpResponseHeader_Start(&response_header, "200", "OK");
- HttpResponseHeader_AppendField(&response_header, "Content-Type", "application/json");
- HttpResponseHeader_AppendField(&response_header, "Date", Rfc822DateNow());
- HttpResponseHeader_EndWithContentLength(&response_header, DynamicBuffer_Size(&output));
-
- send(client_sock_fd, HttpResponseHeader_AsString(&response_header), HttpResponseHeader_Size(&response_header), 0);
- send(client_sock_fd, DynamicBuffer_Buffer(&output), DynamicBuffer_Size(&output), 0);
-
- close(client_sock_fd);
- client_sock_fd = -1;
- }
-
- DynamicBuffer_Destruct(&cache);
- HttpResponseHeader_Destruct(&response_header);
- }
-
- int main(int argc, char *argv[])
- {
- TinyHttpServerRun("0.0.0.0", 8898);
- return EXIT_SUCCESS;
- }
|