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 }