comparison seobeo/snapshot_creator.c @ 126:e7899c93da77

Remove playground.
author June Park <parkjune1995@gmail.com>
date Thu, 08 Jan 2026 18:03:34 -0800
parents 6626ec933933
children 7eb79fd91c7e
comparison
equal deleted inserted replaced
125:f236c895604e 126:e7899c93da77
1 #include "seobeo/snapshot_creator.h" 1 #include "seobeo/snapshot_creator.h"
2 #include "seobeo/seobeo_internal.h"
2 #include <stdio.h> 3 #include <stdio.h>
3 #include <stdlib.h> 4 #include <stdlib.h>
4 #include <string.h> 5 #include <string.h>
5 #include <sys/stat.h> 6 #include <sys/stat.h>
6 #include <unistd.h> 7 #include <unistd.h>
7 8
8 #define MAX_RESPONSE_SIZE (1024 * 1024)
9
10 // Helper: Convert URL path to filename
11 static void path_to_filename(const char *path, char *filename, size_t max_len) 9 static void path_to_filename(const char *path, char *filename, size_t max_len)
12 { 10 {
13 if (strcmp(path, "/") == 0) 11 if (strcmp(path, "/") == 0)
14 { 12 {
15 snprintf(filename, max_len, "root.snapshot"); 13 snprintf(filename, max_len, "root.snapshot");
16 return; 14 return;
17 } 15 }
18 16
19 const char *p = path; 17 const char *p = path;
20 if (*p == '/') 18 if (*p == '/')
21 {
22 p++; 19 p++;
23 }
24 20
25 char *out = filename; 21 char *out = filename;
26 size_t remaining = max_len - 1; 22 size_t remaining = max_len - 1;
27 23
28 while (*p && remaining > 0) 24 while (*p && remaining > 0)
67 } 63 }
68 } 64 }
69 return mkdir(tmp, 0755); 65 return mkdir(tmp, 0755);
70 } 66 }
71 67
72 // Helper: Generate HTTP GET request 68 // Helper: Build full HTTP response from Seobeo_Client_Response
73 static int generate_http_get(char *buffer, size_t size, const char *path, const char *host) 69 static char* build_full_response(Seobeo_Client_Response *p_resp, size_t *len_out)
74 { 70 {
75 return snprintf( 71 if (!p_resp)
76 buffer, size, 72 return NULL;
77 "GET %s HTTP/1.1\r\n" 73
78 "Host: %s\r\n" 74 // Calculate total response size
79 "Connection: close\r\n" 75 size_t status_line_len = 100; // "HTTP/1.1 200 OK\r\n"
80 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 76 size_t headers_len = 0;
81 "User-Agent: SeobeoSnapshotCreator/1.0\r\n" 77 size_t body_len = p_resp->body_length;
82 "\r\n", 78
83 path, host 79 // Estimate header size
84 ); 80 if (p_resp->headers)
85 } 81 {
86 82 size_t header_count = Dowa_Array_Length(p_resp->headers);
87 // Helper: Read full HTTP response 83 for (size_t i = 0; i < header_count; i++)
88 static char* read_full_response(Seobeo_Handle *client, size_t *len_out) 84 {
89 { 85 headers_len += strlen(p_resp->headers[i].key) + strlen(p_resp->headers[i].value) + 4; // ": " + "\r\n"
90 char *response = malloc(MAX_RESPONSE_SIZE); 86 }
87 }
88
89 size_t total_size = status_line_len + headers_len + 2 + body_len + 1; // +2 for "\r\n", +1 for null terminator
90 char *response = malloc(total_size);
91 if (!response) 91 if (!response)
92 {
93 return NULL; 92 return NULL;
94 } 93
95 94 // Build status line
96 size_t total = 0; 95 int offset = snprintf(response, total_size, "HTTP/1.1 %d %s\r\n",
97 int attempts = 0; 96 p_resp->status_code,
98 const int max_attempts = 100; 97 p_resp->status_text ? p_resp->status_text : "OK");
99 98
100 while (attempts++ < max_attempts && total < MAX_RESPONSE_SIZE - 1) 99 // Add headers
101 { 100 if (p_resp->headers)
102 int n = Seobeo_Handle_Read(client); 101 {
103 102 size_t header_count = Dowa_Array_Length(p_resp->headers);
104 if (n > 0) 103 for (size_t i = 0; i < header_count; i++)
105 { 104 {
106 size_t to_copy = client->read_buffer_len; 105 offset += snprintf(response + offset, total_size - offset, "%s: %s\r\n",
107 if (total + to_copy > MAX_RESPONSE_SIZE - 1) 106 p_resp->headers[i].key,
108 { 107 p_resp->headers[i].value);
109 to_copy = MAX_RESPONSE_SIZE - 1 - total; 108 }
110 } 109 }
111 110
112 memcpy(response + total, client->read_buffer, to_copy); 111 // End of headers
113 total += to_copy; 112 offset += snprintf(response + offset, total_size - offset, "\r\n");
114 Seobeo_Handle_Consume(client, (uint32)to_copy); 113
115 } 114 // Add body
116 else if (n == -2) 115 if (p_resp->body && body_len > 0)
117 { 116 {
118 break; 117 memcpy(response + offset, p_resp->body, body_len);
119 } 118 offset += body_len;
120 else if (n == 0) 119 }
121 { 120
122 usleep(10000); 121 response[offset] = '\0';
123 continue; 122 *len_out = offset;
124 }
125 else
126 {
127 free(response);
128 return NULL;
129 }
130 }
131
132 response[total] = '\0';
133 *len_out = total;
134 return response; 123 return response;
135 } 124 }
136 125
137 // Helper: Write snapshot to file 126 // Helper: Write snapshot to file
138 static int write_snapshot(const char *filepath, const char *data, size_t size) 127 static int write_snapshot(const char *filepath, const char *data, size_t size)
169 return -1; 158 return -1;
170 } 159 }
171 160
172 printf("Creating snapshot: %s (expecting %d)\n", config->path, config->expected_status); 161 printf("Creating snapshot: %s (expecting %d)\n", config->path, config->expected_status);
173 162
174 // Connect to server 163 // Build URL
175 Seobeo_Handle *client = Seobeo_Stream_Handle_Client_Create(config->host, config->port, FALSE); 164 char url[2048];
176 if (!client || client->socket < 0) 165 snprintf(url, sizeof(url), "http://%s:%s%s", config->host, config->port, config->path);
177 { 166
178 fprintf(stderr, " ✗ Failed to connect to %s:%s\n", config->host, config->port); 167 // Create HTTP request
179 if (client) 168 Seobeo_Client_Request *p_req = Seobeo_Client_Request_Create(url);
180 { 169 if (!p_req)
181 Seobeo_Handle_Destroy(client); 170 {
182 } 171 fprintf(stderr, " ✗ Failed to create request for %s\n", url);
183 return -1; 172 return -1;
184 } 173 }
185 174
186 // Send GET request 175 // Execute request
187 char request[4096]; 176 Seobeo_Client_Response *p_resp = Seobeo_Client_Request_Execute(p_req);
188 int req_len = generate_http_get(request, sizeof(request), config->path, config->host); 177 if (!p_resp)
189 Seobeo_Handle_Queue(client, (uint8*)request, (uint32)req_len); 178 {
190 179 fprintf(stderr, " ✗ Failed to get response\n");
191 if (Seobeo_Handle_Flush(client) < 0) 180 Seobeo_Client_Request_Destroy(p_req);
192 { 181 return -1;
193 fprintf(stderr, " ✗ Failed to send request\n"); 182 }
194 Seobeo_Handle_Destroy(client); 183
195 return -1; 184 // Check status code
196 } 185 if (p_resp->status_code != config->expected_status)
197 186 {
198 // Read response 187 fprintf(stderr, " ✗ Status mismatch: expected %d, got %d\n",
188 config->expected_status, p_resp->status_code);
189 Seobeo_Client_Response_Destroy(p_resp);
190 Seobeo_Client_Request_Destroy(p_req);
191 return -1;
192 }
193
194 printf(" ✓ Status: %d\n", p_resp->status_code);
195
196 // Build full HTTP response
199 size_t response_len = 0; 197 size_t response_len = 0;
200 char *response = read_full_response(client, &response_len); 198 char *response = build_full_response(p_resp, &response_len);
201 Seobeo_Handle_Destroy(client); 199
200 Seobeo_Client_Response_Destroy(p_resp);
201 Seobeo_Client_Request_Destroy(p_req);
202 202
203 if (!response || response_len == 0) 203 if (!response || response_len == 0)
204 { 204 {
205 fprintf(stderr, " ✗ Failed to read response\n"); 205 fprintf(stderr, " ✗ Failed to build response\n");
206 if (response) 206 if (response)
207 {
208 free(response); 207 free(response);
209 } 208 return -1;
210 return -1; 209 }
211 }
212
213 // Parse status code
214 int status = -1;
215 const char *status_line = strstr(response, "HTTP/1.1 ");
216 if (!status_line)
217 {
218 status_line = strstr(response, "HTTP/1.0 ");
219 }
220 if (status_line)
221 {
222 sscanf(status_line + 9, "%d", &status);
223 }
224
225 if (status != config->expected_status)
226 {
227 fprintf(stderr, " ✗ Status mismatch: expected %d, got %d\n",
228 config->expected_status, status);
229 free(response);
230 return -1;
231 }
232
233 printf(" ✓ Status: %d\n", status);
234 210
235 // Generate snapshot filename 211 // Generate snapshot filename
236 char filename[256]; 212 char filename[256];
237 path_to_filename(config->path, filename, sizeof(filename)); 213 path_to_filename(config->path, filename, sizeof(filename));
238 214