Mercurial
comparison seobeo/s_web.c @ 221:ce7f4400c2de hg-web
[hg-web] Harden forge and add changeset UI
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 09:01:24 -0700 |
| parents | a69485d9f2e1 |
| children | 0e7b9464248d |
comparison
equal
deleted
inserted
replaced
| 219:8c9bb0b0759e | 221:ce7f4400c2de |
|---|---|
| 56 case HTTP_BAD_REQUEST: status_text = "Bad Request"; break; | 56 case HTTP_BAD_REQUEST: status_text = "Bad Request"; break; |
| 57 case HTTP_UNAUTHORIZED: status_text = "Unauthorized"; break; | 57 case HTTP_UNAUTHORIZED: status_text = "Unauthorized"; break; |
| 58 case HTTP_FORBIDDEN: status_text = "Forbidden"; break; | 58 case HTTP_FORBIDDEN: status_text = "Forbidden"; break; |
| 59 case HTTP_NOT_FOUND: status_text = "Not Found"; break; | 59 case HTTP_NOT_FOUND: status_text = "Not Found"; break; |
| 60 case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break; | 60 case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break; |
| 61 case 502: status_text = "Bad Gateway"; break; | |
| 62 case 504: status_text = "Gateway Timeout"; break; | |
| 61 default: status_text = "Unknown"; break; | 63 default: status_text = "Unknown"; break; |
| 62 } | 64 } |
| 63 | 65 |
| 64 sprintf( | 66 snprintf( |
| 65 buffer, | 67 (char*)buffer, 1024, |
| 66 "HTTP/1.1 %d %s\r\n" | 68 "HTTP/1.1 %d %s\r\n" |
| 67 "Content-Type: %s\r\n" | 69 "Content-Type: %s\r\n" |
| 68 "Content-Length: %d\r\n" | 70 "Content-Length: %d\r\n" |
| 69 "Connection: %s\r\n" | 71 "Connection: %s\r\n" |
| 70 "\r\n", | 72 "\r\n", |
| 772 Dowa_Arena *p_arena) | 774 Dowa_Arena *p_arena) |
| 773 { | 775 { |
| 774 Seobeo_Router_Send_Response_KeepAlive(p_handle, p_response_map, p_arena, FALSE); | 776 Seobeo_Router_Send_Response_KeepAlive(p_handle, p_response_map, p_arena, FALSE); |
| 775 } | 777 } |
| 776 | 778 |
| 779 static boolean Seobeo_Response_Header_Value_Is_Safe(const char *value) | |
| 780 { | |
| 781 return value && strchr(value, '\r') == NULL && strchr(value, '\n') == NULL; | |
| 782 } | |
| 783 | |
| 777 void Seobeo_Router_Send_Response_KeepAlive( | 784 void Seobeo_Router_Send_Response_KeepAlive( |
| 778 Seobeo_Handle *p_handle, | 785 Seobeo_Handle *p_handle, |
| 779 Seobeo_Request_Entry *p_response_map, | 786 Seobeo_Request_Entry *p_response_map, |
| 780 Dowa_Arena *p_arena, | 787 Dowa_Arena *p_arena, |
| 781 boolean keep_alive) | 788 boolean keep_alive) |
| 817 body_length = atoi(content_length_str); | 824 body_length = atoi(content_length_str); |
| 818 } | 825 } |
| 819 else | 826 else |
| 820 body_length = strlen(body); | 827 body_length = strlen(body); |
| 821 | 828 |
| 822 char *header = Dowa_Arena_Allocate(p_arena, 4096); | 829 size_t header_capacity = 1024; |
| 823 Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); | |
| 824 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) | 830 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) |
| 825 { | 831 { |
| 832 const char *key = p_response_map[i].key; | |
| 833 const char *value = p_response_map[i].value; | |
| 826 if ( | 834 if ( |
| 827 strstr(p_response_map[i].key, "status") || | 835 strcasecmp(key, "status") == 0 || |
| 828 strstr(p_response_map[i].key, "body") || | 836 strcasecmp(key, "body") == 0 || |
| 829 strstr(p_response_map[i].key, "content-type") || | 837 strcasecmp(key, "content-type") == 0 || |
| 830 strstr(p_response_map[i].key, "content-length") | 838 strcasecmp(key, "content-length") == 0 |
| 831 ) | 839 ) |
| 832 continue; | 840 continue; |
| 833 | 841 if (Seobeo_Response_Header_Value_Is_Safe(key) && |
| 834 int32 current_header_len = strlen(header); | 842 Seobeo_Response_Header_Value_Is_Safe(value)) |
| 835 char *temp = malloc(sizeof(char) * 1024); | 843 header_capacity += strlen(key) + strlen(value) + 4; |
| 836 sprintf(temp, "%s: %s\r\n\r\n", p_response_map[i].key, p_response_map[i].value); | 844 } |
| 837 memcpy(&header[current_header_len - 2 /* \r\n */], temp, strlen(temp)); | 845 |
| 838 free(temp); | 846 char *header = Dowa_Arena_Allocate(p_arena, header_capacity); |
| 839 } | 847 Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); |
| 840 | 848 size_t header_length = strlen(header); |
| 841 printf("hEADER %s\n", header); | 849 if (header_length < 2) |
| 850 return; | |
| 851 header_length -= 2; | |
| 852 | |
| 853 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) | |
| 854 { | |
| 855 const char *key = p_response_map[i].key; | |
| 856 const char *value = p_response_map[i].value; | |
| 857 if ( | |
| 858 strcasecmp(key, "status") == 0 || | |
| 859 strcasecmp(key, "body") == 0 || | |
| 860 strcasecmp(key, "content-type") == 0 || | |
| 861 strcasecmp(key, "content-length") == 0 | |
| 862 ) | |
| 863 continue; | |
| 864 | |
| 865 if (!Seobeo_Response_Header_Value_Is_Safe(key) || | |
| 866 !Seobeo_Response_Header_Value_Is_Safe(value)) | |
| 867 { | |
| 868 Seobeo_Log(SEOBEO_WARNING, "Skipping unsafe response header\n"); | |
| 869 continue; | |
| 870 } | |
| 871 | |
| 872 int written = snprintf( | |
| 873 header + header_length, | |
| 874 header_capacity - header_length, | |
| 875 "%s: %s\r\n", | |
| 876 key, | |
| 877 value); | |
| 878 if (written < 0 || (size_t)written >= header_capacity - header_length) | |
| 879 { | |
| 880 Seobeo_Log(SEOBEO_ERROR, "Response header exceeded allocated capacity\n"); | |
| 881 return; | |
| 882 } | |
| 883 header_length += (size_t)written; | |
| 884 } | |
| 885 memcpy(header + header_length, "\r\n", 3); | |
| 842 | 886 |
| 843 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); | 887 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); |
| 844 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); | 888 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); |
| 845 Seobeo_Handle_Flush(p_handle); | 889 Seobeo_Handle_Flush(p_handle); |
| 846 } | 890 } |