#include #include #include "utils/url.h" #include "utils/nsurl.h" #include "utils/utils.h" #include "utils/corestrings.h" #include "utils/nsurl.h" #include "utils/log.h" #include "content/fetch.h" #include "content/fetchers.h" #include "content/fetchers/httplib_kolibri.h" #include "frontends/kolibrios/kolibri_http.h" #define STOP __asm__ __volatile__("int3") extern struct fetch; struct httpfetcher { struct http_msg *handle; struct fetch *owner; bool headercbdone; struct httpfetcher *next; }; struct httpfetcher *head = NULL; void add_to_poll(struct httpfetcher *newfetcher) { LOG("-=- add: newfetcher 0x%x, newfetcher->handle 0x%x", newfetcher, newfetcher->handle); /* STOP; */ struct httpfetcher *t = head; assert(newfetcher->next == NULL); if(head == NULL) { head = newfetcher; LOG("-=- head was NULL. head is now : 0x%x", head); assert(head->next == NULL); } else { while(t->next != NULL) { LOG("-=- Passing through httpfetcher : 0x%x", t); t = t->next; } LOG("-=- Adding after httpfetcher : 0x%x", t); t->next = newfetcher; } LOG("-=- done: newfetcher 0x%x, newfetcher->handle 0x%x", newfetcher, newfetcher->handle); } void remove_from_poll(struct http_msg *donehttp) { struct httpfetcher *t = head, *p = head; LOG("-=- remove: (->handle) donehttp 0x%x", donehttp); /* STOP; */ while(t) { LOG("------- t = 0x%x, t->handle = 0x%x", t, t->handle); /* STOP; */ if (t->handle == donehttp) { LOG(" -- t->handle == donehttp"); if(t == head) { LOG("--- t == head"); p = t->next; head = p; LOG("-=- Setting head to 0x%x", p); break; } else { LOG("--- t != head"); LOG("-=- p is 0x%x", p); p->next = t->next; break; } } p = t; t = t->next; } } bool init_fetcher(lwc_string *scheme) { bool supported_scheme; assert(lwc_string_isequal(scheme, corestring_lwc_http, &supported_scheme) == lwc_error_ok); kolibri_http_init(); /* if(supported_scheme) { */ /* if(kolibri_http_init() == 0) */ /* debug_board_printf("[INFO] Loaded http.obj library successfully.\n"); */ /* else { */ /* debug_board_printf("[ERROR] Could not load http.obj library.\n"); */ /* return false; */ /* } */ /* } */ return supported_scheme; } bool supported_url_check(const struct nsurl *url) { bool supported; lwc_string *url_scheme = nsurl_get_component(url, NSURL_SCHEME); assert(lwc_string_isequal(url_scheme, corestring_lwc_http, &supported) == lwc_error_ok); lwc_string_unref(url_scheme); return supported; } void *setup_fetch(struct fetch *parent_fetch, struct nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct http_msg* request = NULL; LOG("[SETUP] Our target URL: %s", nsurl_access(url)); LOG("[SETUP] POST urlencoded data: %s", post_urlenc); LOG("[SETUP] Headers : %s", *headers); struct fetch_multipart_data *printer = post_multipart; while(printer != NULL) { LOG("Multipart POST : (%s = %s)\n", printer->name, printer->value); printer = printer->next; } if(post_multipart != NULL) LOG("[WARNING] We dont support POST multipart yet!\n"); if(post_urlenc) { LOG("http_post: %s", nsurl_access(url)); request = http_post_asm(nsurl_access(url), NULL, 0, *headers, post_urlenc, strlen(post_urlenc)); } else { /* Do a GET */ LOG("http_get: %s", nsurl_access(url)); request = http_get_asm(nsurl_access(url), NULL, 0, *headers); } LOG("Address of request : 0x%x", request); assert(request != NULL); if(request == NULL) { LOG("[ERROR] Cannot allocate more memory for http library handle creation."); return NULL; } struct httpfetcher *newfetcher = (struct httpfetcher *) malloc(sizeof(struct httpfetcher)); assert(newfetcher); newfetcher->next = NULL; newfetcher->handle = request; newfetcher->headercbdone = false; newfetcher->owner = parent_fetch; return newfetcher; } bool start_fetch(void *httpf) { LOG("-=- start_fetch : httpf: 0x%x", httpf); add_to_poll((struct httpfetcher *) httpf); return true; } bool abort_fetch(void *httpf) { LOG("aborting fetch 0x%x", ((struct httpfetcher *)httpf)->owner); http_disconnect_asm(((struct httpfetcher *)httpf)->handle); remove_from_poll(((struct httpfetcher *) httpf)->handle); fetch_remove_from_queues(((struct httpfetcher *)httpf)->owner); /* fetch_free(((struct httpfetcher *)httpf)->owner); */ return true; } bool free_fetch(void *httpf) { LOG("Freeing fetch 0x%x", ((struct httpfetcher *)httpf)->owner); http_free_asm((((struct httpfetcher *)httpf)->handle)); free((struct httpfetcher *)httpf); return true; } void poll_fetch(lwc_string *scheme) { bool supported_scheme; assert(lwc_string_isequal(scheme, corestring_lwc_http, &supported_scheme) == lwc_error_ok); assert(supported_scheme); struct httpfetcher *t = head; while(t != NULL) { LOG("-- Polling for t 0x%x, http_msg 0x%x, fetch 0x%x [ hcbdone = %s ]", t, t->handle, t->owner, t->headercbdone == true ? "true" : "false"); LOG("--- http_msg struct at : %x", t->handle); LOG("--- Header starts at : %x", &(t->handle->http_header)); LOG("--- Header Length: %d", t->handle->header_length); LOG("--- Content starts at : %x", &(t->handle->content_ptr)); LOG("--- Content Length (received / total): %d / %d", t->handle->content_received, t->handle->content_length); int ret = http_receive_asm(t->handle); if(t->handle->flags & HTTP_ERRORS) { fetch_msg msg; msg.type = FETCH_ERROR; LOG("---- [ERROR] http_msg -> flags = 0x%x", t->handle->flags); msg.data.header_or_data.buf = (const uint8_t *) "HTTPLIB ERROR"; msg.data.header_or_data.len = strlen("HTTPLIB ERROR"); fetch_send_callback(&msg, t->owner); t->headercbdone = true; } if(t->headercbdone == false) { if (t->handle->flags & HTTP_GOT_HEADER) { LOG("---- Received all HTTP Headers."); LOG("---- response status code = %d", t->handle->status); fetch_set_http_code(t->owner, t->handle->status); if(t->handle->status >= 200 && t->handle->status < 300) { fetch_msg msg; int plen = 0; char *ptr = &(t->handle->http_header); while(plen < t->handle->header_length) { int j = plen; for(;;j++) { if(*(ptr + j) == '\r') break; } msg.type = FETCH_HEADER; msg.data.header_or_data.buf = (const uint8_t *)(ptr + plen); msg.data.header_or_data.len = j - plen; char *xx = (char *) malloc(j - plen + 1); strncpy(xx, ptr + plen, j-plen); xx[j-plen] = '\0'; LOG("Headerline: %s", xx); fetch_send_callback(&msg, t->owner); free(xx); plen = j + 2; } t->headercbdone = true; } else if(t->handle->status >= 300 && t->handle->status < 400) { if(t->handle->status == 304) { fetch_msg msg; msg.type = FETCH_NOTMODIFIED; fetch_send_callback(&msg, t->owner); remove_from_poll(t->handle); /* t = t->next; */ t = head; continue; } else { LOG("---- finding header 'location' for fetch 0x%x", t->owner); fetch_msg msg; int lenloc = 0; char *tmp = http_find_header_field_asm(t->handle, "location"); while(!isspace(*(tmp + lenloc))) lenloc++; msg.type = FETCH_REDIRECT; char *newlocation = malloc(lenloc + 1); strncpy(newlocation, tmp, lenloc); newlocation[lenloc]='\0'; msg.data.redirect = newlocation; LOG("---- [3xx] : Redirect to %s", msg.data.redirect); fetch_send_callback(&msg, t->owner); t->headercbdone = true; LOG("---- call Remove t->handle = 0x%x", t->handle); remove_from_poll(t->handle); /* t = t->next; */ t = head; continue; } } else { fetch_msg msg; msg.type = FETCH_ERROR; LOG(" ---- [ERROR] Unhandled HTTP Code : %d", t->handle->status); fetch_send_callback(&msg, t->owner); t->headercbdone = true; remove_from_poll(t->handle); fetch_remove_from_queues(t->owner); /* fetch_free(t->owner); */ /* t = t->next; */ t = head; continue; } } else { LOG("---- Headers not received yet."); } } else if(ret == 0) { fetch_msg msg; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *)t->handle->content_ptr; msg.data.header_or_data.len = t->handle->content_length; fetch_send_callback(&msg, t->owner); LOG("---- FETCH_FINISHED for fetch 0x%x", t->owner); msg.type = FETCH_FINISHED; msg.data.header_or_data.buf = NULL; msg.data.header_or_data.len = 0; fetch_send_callback(&msg, t->owner); struct httpfetcher *tnext = t->next; remove_from_poll(t->handle); fetch_remove_from_queues(t->owner); /* fetch_free(t->owner); */ t = head; /* t = tnext; */ continue; } LOG("Main loop: t going from 0x%x to 0x%x", t->owner, t->next != NULL ? t->next->owner : "0"); t = t->next; } LOG("=Returning from %s", __func__); } void finalize_fetcher(lwc_string *scheme) { bool supported_scheme; assert(lwc_string_isequal(scheme, corestring_lwc_http, &supported_scheme) == lwc_error_ok); lwc_string_unref(scheme); } static struct fetcher_operation_table fetcher_ops = { .initialise = init_fetcher, .acceptable = supported_url_check, .setup = setup_fetch, .start = start_fetch, .abort = abort_fetch, .free = free_fetch, .poll = poll_fetch, .finalise = finalize_fetcher }; nserror fetch_httplib_kolibri_register(void) { lwc_string *scheme = lwc_string_ref(corestring_lwc_http); return fetcher_add(scheme, &fetcher_ops); }