naett_core.c (10940B)
1 #include "naett_internal.h" 2 #include <stdarg.h> 3 #include <stdlib.h> 4 #include <stddef.h> 5 #include <string.h> 6 #include <assert.h> 7 8 typedef struct InternalParam* InternalParamPtr; 9 typedef void (*ParamSetter)(InternalParamPtr param, InternalRequest* req); 10 11 typedef struct InternalParam { 12 ParamSetter setter; 13 int offset; 14 union { 15 int integer; 16 const char* string; 17 struct { 18 const char* key; 19 const char* value; 20 } kv; 21 void* ptr; 22 void (*func)(void); 23 }; 24 } InternalParam; 25 26 typedef struct InternalOption { 27 #define maxParams 2 28 int numParams; 29 InternalParam params[maxParams]; 30 } InternalOption; 31 32 static void stringSetter(InternalParamPtr param, InternalRequest* req) { 33 char* stringCopy = strdup(param->string); 34 char* opaque = (char*)&req->options; 35 char** stringField = (char**)(opaque + param->offset); 36 if (*stringField) { 37 free(*stringField); 38 } 39 *stringField = stringCopy; 40 } 41 42 static void intSetter(InternalParamPtr param, InternalRequest* req) { 43 char* opaque = (char*)&req->options; 44 int* intField = (int*)(opaque + param->offset); 45 *intField = param->integer; 46 } 47 48 static void ptrSetter(InternalParamPtr param, InternalRequest* req) { 49 char* opaque = (char*)&req->options; 50 void** ptrField = (void**)(opaque + param->offset); 51 *ptrField = param->ptr; 52 } 53 54 static void kvSetter(InternalParamPtr param, InternalRequest* req) { 55 char* opaque = (char*)&req->options; 56 KVLink** kvField = (KVLink**)(opaque + param->offset); 57 58 naettAlloc(KVLink, newNode); 59 newNode->key = strdup(param->kv.key); 60 newNode->value = strdup(param->kv.value); 61 newNode->next = *kvField; 62 63 *kvField = newNode; 64 } 65 66 static int defaultBodyReader(void* dest, int bufferSize, void* userData) { 67 Buffer* buffer = (Buffer*) userData; 68 69 if (dest == NULL) { 70 return buffer->size; 71 } 72 73 int bytesToRead = buffer->size - buffer->position; 74 if (bytesToRead > bufferSize) { 75 bytesToRead = bufferSize; 76 } 77 78 const char* source = ((const char*)buffer->data) + buffer->position; 79 memcpy(dest, source, bytesToRead); 80 buffer->position += bytesToRead; 81 return bytesToRead; 82 } 83 84 static int defaultBodyWriter(const void* source, int bytes, void* userData) { 85 Buffer* buffer = (Buffer*) userData; 86 int newCapacity = buffer->capacity; 87 if (newCapacity == 0) { 88 newCapacity = bytes; 89 } 90 while (newCapacity - buffer->size < bytes) { 91 newCapacity *= 2; 92 } 93 if (newCapacity != buffer->capacity) { 94 buffer->data = realloc(buffer->data, newCapacity); 95 buffer->capacity = newCapacity; 96 } 97 char* dest = ((char*)buffer->data) + buffer->size; 98 memcpy(dest, source, bytes); 99 buffer->size += bytes; 100 return bytes; 101 } 102 103 static int initialized = 0; 104 105 static void initRequest(InternalRequest* req, const char* url) { 106 assert(initialized); 107 req->options.method = strdup("GET"); 108 req->options.timeoutMS = 5000; 109 req->url = strdup(url); 110 } 111 112 static void applyOptionParams(InternalRequest* req, InternalOption* option) { 113 for (int j = 0; j < option->numParams; j++) { 114 InternalParam* param = option->params + j; 115 param->setter(param, req); 116 } 117 } 118 119 // Public API 120 121 void naettInit(naettInitData initData) { 122 assert(!initialized); 123 naettPlatformInit(initData); 124 initialized = 1; 125 } 126 127 naettOption* naettMethod(const char* method) { 128 naettAlloc(InternalOption, option); 129 option->numParams = 1; 130 InternalParam* param = &option->params[0]; 131 132 param->string = method; 133 param->offset = offsetof(RequestOptions, method); 134 param->setter = stringSetter; 135 136 return (naettOption*)option; 137 } 138 139 naettOption* naettHeader(const char* name, const char* value) { 140 naettAlloc(InternalOption, option); 141 option->numParams = 1; 142 InternalParam* param = &option->params[0]; 143 144 param->kv.key = name; 145 param->kv.value = value; 146 param->offset = offsetof(RequestOptions, headers); 147 param->setter = kvSetter; 148 149 return (naettOption*)option; 150 } 151 152 naettOption* naettUserAgent(const char* userAgent) { 153 naettAlloc(InternalOption, option); 154 option->numParams = 1; 155 InternalParam* param = &option->params[0]; 156 157 param->string = userAgent; 158 param->offset = offsetof(RequestOptions, userAgent); 159 param->setter = stringSetter; 160 161 return (naettOption*)option; 162 } 163 164 naettOption* naettTimeout(int timeoutMS) { 165 naettAlloc(InternalOption, option); 166 option->numParams = 1; 167 InternalParam* param = &option->params[0]; 168 169 param->integer = timeoutMS; 170 param->offset = offsetof(RequestOptions, timeoutMS); 171 param->setter = intSetter; 172 173 return (naettOption*)option; 174 } 175 176 naettOption* naettBody(const char* body, int size) { 177 naettAlloc(InternalOption, option); 178 option->numParams = 2; 179 180 InternalParam* bodyParam = &option->params[0]; 181 InternalParam* sizeParam = &option->params[1]; 182 183 bodyParam->ptr = (void*)body; 184 bodyParam->offset = offsetof(RequestOptions, body) + offsetof(Buffer, data); 185 bodyParam->setter = ptrSetter; 186 187 sizeParam->integer = size; 188 sizeParam->offset = offsetof(RequestOptions, body) + offsetof(Buffer, size); 189 sizeParam->setter = intSetter; 190 191 return (naettOption*)option; 192 } 193 194 naettOption* naettBodyReader(naettReadFunc reader, void* userData) { 195 naettAlloc(InternalOption, option); 196 option->numParams = 2; 197 198 InternalParam* readerParam = &option->params[0]; 199 InternalParam* dataParam = &option->params[1]; 200 201 readerParam->func = (void (*)(void)) reader; 202 readerParam->offset = offsetof(RequestOptions, bodyReader); 203 readerParam->setter = ptrSetter; 204 205 dataParam->ptr = userData; 206 dataParam->offset = offsetof(RequestOptions, bodyReaderData); 207 dataParam->setter = ptrSetter; 208 209 return (naettOption*)option; 210 } 211 212 naettOption* naettBodyWriter(naettWriteFunc writer, void* userData) { 213 naettAlloc(InternalOption, option); 214 option->numParams = 2; 215 216 InternalParam* writerParam = &option->params[0]; 217 InternalParam* dataParam = &option->params[1]; 218 219 writerParam->func = (void(*)(void)) writer; 220 writerParam->offset = offsetof(RequestOptions, bodyWriter); 221 writerParam->setter = ptrSetter; 222 223 dataParam->ptr = userData; 224 dataParam->offset = offsetof(RequestOptions, bodyWriterData); 225 dataParam->setter = ptrSetter; 226 227 return (naettOption*)option; 228 } 229 230 void setupDefaultRW(InternalRequest* req) { 231 if (req->options.bodyReader == NULL) { 232 req->options.bodyReader = defaultBodyReader; 233 req->options.bodyReaderData = (void*) &req->options.body; 234 } 235 if (req->options.bodyReader == defaultBodyReader) { 236 req->options.body.position = 0; 237 } 238 if (req->options.bodyWriter == NULL) { 239 req->options.bodyWriter = defaultBodyWriter; 240 } 241 } 242 243 naettReq* naettRequest_va(const char* url, int numArgs, ...) { 244 assert(url != NULL); 245 246 va_list args; 247 InternalOption* option; 248 naettAlloc(InternalRequest, req); 249 initRequest(req, url); 250 251 va_start(args, numArgs); 252 for (int i = 0; i < numArgs; i++) { 253 option = va_arg(args, InternalOption*); 254 applyOptionParams(req, option); 255 free(option); 256 } 257 va_end(args); 258 259 setupDefaultRW(req); 260 261 if (naettPlatformInitRequest(req)) { 262 return (naettReq*)req; 263 } 264 265 naettFree((naettReq*) req); 266 return NULL; 267 } 268 269 naettReq* naettRequestWithOptions(const char* url, int numOptions, const naettOption** options) { 270 assert(url != NULL); 271 assert(numOptions == 0 || options != NULL); 272 273 naettAlloc(InternalRequest, req); 274 initRequest(req, url); 275 276 for (int i = 0; i < numOptions; i++) { 277 InternalOption* option = (InternalOption*)options[i]; 278 applyOptionParams(req, option); 279 free(option); 280 } 281 282 setupDefaultRW(req); 283 284 if (naettPlatformInitRequest(req)) { 285 return (naettReq*)req; 286 } 287 288 naettFree((naettReq*) req); 289 return NULL; 290 } 291 292 naettRes* naettMake(naettReq* request) { 293 assert(initialized); 294 assert(request != NULL); 295 296 InternalRequest* req = (InternalRequest*)request; 297 naettAlloc(InternalResponse, res); 298 res->request = req; 299 300 if (req->options.bodyWriter == defaultBodyWriter) { 301 req->options.bodyWriterData = (void*) &res->body; 302 } 303 304 naettPlatformMakeRequest(res); 305 return (naettRes*) res; 306 } 307 308 const void* naettGetBody(naettRes* response, int* size) { 309 assert(response != NULL); 310 assert(size != NULL); 311 312 InternalResponse* res = (InternalResponse*)response; 313 *size = res->body.size; 314 return res->body.data; 315 } 316 317 int naettGetTotalBytesRead(naettRes* response, int* totalSize) { 318 assert(response != NULL); 319 assert(totalSize != NULL); 320 321 InternalResponse* res = (InternalResponse*)response; 322 *totalSize = res->contentLength; 323 return res->totalBytesRead; 324 } 325 326 const char* naettGetHeader(naettRes* response, const char* name) { 327 assert(response != NULL); 328 assert(name != NULL); 329 330 InternalResponse* res = (InternalResponse*)response; 331 KVLink* node = res->headers; 332 while (node) { 333 if (strcasecmp(name, node->key) == 0) { 334 return node->value; 335 } 336 node = node->next; 337 } 338 return NULL; 339 } 340 341 void naettListHeaders(naettRes* response, naettHeaderLister lister, void* userData) { 342 assert(response != NULL); 343 assert(lister != NULL); 344 345 InternalResponse* res = (InternalResponse*)response; 346 KVLink* node = res->headers; 347 while (node) { 348 if (!lister(node->key, node->value, userData)) { 349 return; 350 } 351 node = node->next; 352 } 353 } 354 355 naettReq* naettGetRequest(naettRes* response) { 356 assert(response != NULL); 357 InternalResponse* res = (InternalResponse*)response; 358 return (naettReq*) res->request; 359 } 360 361 int naettComplete(const naettRes* response) { 362 assert(response != NULL); 363 InternalResponse* res = (InternalResponse*)response; 364 return res->complete; 365 } 366 367 int naettGetStatus(const naettRes* response) { 368 assert(response != NULL); 369 InternalResponse* res = (InternalResponse*)response; 370 return res->code; 371 } 372 373 static void freeKVList(KVLink* node) { 374 while (node != NULL) { 375 free((void*) node->key); 376 free((void*) node->value); 377 KVLink* next = node->next; 378 free(node); 379 node = next; 380 } 381 } 382 383 void naettFree(naettReq* request) { 384 assert(request != NULL); 385 386 InternalRequest* req = (InternalRequest*)request; 387 naettPlatformFreeRequest(req); 388 KVLink* node = req->options.headers; 389 freeKVList(node); 390 free((void*)req->options.method); 391 free((void*)req->url); 392 free(request); 393 } 394 395 void naettClose(naettRes* response) { 396 assert(response != NULL); 397 398 InternalResponse* res = (InternalResponse*)response; 399 res->request = NULL; 400 naettPlatformCloseResponse(res); 401 KVLink* node = res->headers; 402 freeKVList(node); 403 free(res->body.data); 404 free(response); 405 }