From 28f974f00f43d3a04c0bcae32e7cfc85ee66df20 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sat, 25 Oct 2003 14:13:49 +0000 Subject: [project @ 2003-10-25 14:13:49 by bursa] URL encoded POST support. svn path=/import/netsurf/; revision=375 --- content/fetch.c | 31 ++++++++++++++++++--- content/fetch.h | 4 ++- content/fetchcache.c | 6 +++-- content/fetchcache.h | 5 +++- css/css.c | 8 +++--- debug/netsurfd.c | 2 +- desktop/browser.c | 74 ++++++++++++++++++++++++++++++++------------------- desktop/browser.h | 4 ++- render/box.c | 36 ++++++++++++++++--------- render/form.c | 2 +- render/form.h | 10 ++++--- render/html.c | 14 +++++----- riscos/401login.c | 2 +- riscos/gui.c | 3 ++- riscos/mouseactions.c | 2 +- 15 files changed, 135 insertions(+), 68 deletions(-) diff --git a/content/fetch.c b/content/fetch.c index 88b451523..f95d7138b 100644 --- a/content/fetch.c +++ b/content/fetch.c @@ -29,6 +29,7 @@ #endif #include "netsurf/desktop/options.h" #include "netsurf/desktop/401login.h" +#include "netsurf/render/form.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/utils.h" @@ -52,6 +53,7 @@ struct fetch { char *location; /**< Response Location header, or 0. */ unsigned long content_length; /**< Response Content-Length, or 0. */ char *realm; /**< HTTP Auth Realm */ + char *post_urlenc; /**< Url encoded POST string, or 0. */ struct fetch *queue; /**< Next fetch for this host. */ struct fetch *prev; /**< Previous active fetch in ::fetch_list. */ struct fetch *next; /**< Next active fetch in ::fetch_list. */ @@ -138,8 +140,9 @@ void fetch_quit(void) */ struct fetch * fetch_start(char *url, char *referer, - void (*callback)(fetch_msg msg, void *p, char *data, unsigned long size), - void *p, bool only_2xx) + void (*callback)(fetch_msg msg, void *p, char *data, unsigned long size), + void *p, bool only_2xx, char *post_urlenc, + struct form_successful_control *post_multipart) { struct fetch *fetch = xcalloc(1, sizeof(*fetch)), *host_fetch; CURLcode code; @@ -170,6 +173,9 @@ struct fetch * fetch_start(char *url, char *referer, if (uri->server != 0) fetch->host = xstrdup(uri->server); fetch->content_length = 0; + fetch->post_urlenc = 0; + if (post_urlenc) + fetch->post_urlenc = xstrdup(post_urlenc); fetch->queue = 0; fetch->prev = 0; fetch->next = 0; @@ -257,10 +263,19 @@ struct fetch * fetch_start(char *url, char *referer, code = curl_easy_setopt(fetch->curl_handle, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC); assert(code == CURLE_OK); +#ifdef riscos if (LOGIN.string != NULL) { code = curl_easy_setopt(fetch->curl_handle, CURLOPT_USERPWD, LOGIN.string); assert(code == CURLE_OK); } +#endif + + /* POST */ + if (fetch->post_urlenc) { + code = curl_easy_setopt(fetch->curl_handle, + CURLOPT_POSTFIELDS, fetch->post_urlenc); + assert(code == CURLE_OK); + } /* add to the global curl multi handle */ codem = curl_multi_add_handle(curl_multi, fetch->curl_handle); @@ -327,11 +342,18 @@ void fetch_abort(struct fetch *f) code = curl_easy_setopt(fetch->curl_handle, CURLOPT_WRITEHEADER, fetch); assert(code == CURLE_OK); /* TODO: remove referer header if fetch->referer == 0 */ - if (fetch->referer != 0) { + /*if (fetch->referer != 0)*/ { code = curl_easy_setopt(fetch->curl_handle, CURLOPT_REFERER, fetch->referer); assert(code == CURLE_OK); } + /* POST */ + if (fetch->post_urlenc) { + code = curl_easy_setopt(fetch->curl_handle, + CURLOPT_POSTFIELDS, fetch->post_urlenc); + assert(code == CURLE_OK); + } + /* add to the global curl multi handle */ codem = curl_multi_add_handle(curl_multi, fetch->curl_handle); assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM); @@ -346,6 +368,7 @@ void fetch_abort(struct fetch *f) free(f->referer); free(f->location); free(f->realm); + free(f->post_urlenc); xfree(f); } @@ -502,6 +525,7 @@ bool fetch_process_headers(struct fetch *f) return true; } +#ifdef riscos /* handle HTTP 401 (Authentication errors) */ if (http_code == 401) { /* this shouldn't be here... */ @@ -510,6 +534,7 @@ bool fetch_process_headers(struct fetch *f) f->callback(FETCH_ERROR, f->p, "",0); return true; } +#endif /* handle HTTP errors (non 2xx response codes) */ if (f->only_2xx && strncmp(f->url, "http", 4) == 0 && diff --git a/content/fetch.h b/content/fetch.h index ed469de04..762664923 100644 --- a/content/fetch.h +++ b/content/fetch.h @@ -18,11 +18,13 @@ typedef enum {FETCH_TYPE, FETCH_DATA, FETCH_FINISHED, FETCH_ERROR, FETCH_REDIREC struct content; struct fetch; +struct form_successful_control; void fetch_init(void); struct fetch * fetch_start(char *url, char *referer, void (*callback)(fetch_msg msg, void *p, char *data, unsigned long size), - void *p, bool only_2xx); + void *p, bool only_2xx, char *post_urlenc, + struct form_successful_control *post_multipart); void fetch_abort(struct fetch *f); void fetch_poll(void); void fetch_quit(void); diff --git a/content/fetchcache.c b/content/fetchcache.c index cf5bccf47..942f38773 100644 --- a/content/fetchcache.c +++ b/content/fetchcache.c @@ -42,7 +42,8 @@ struct content * fetchcache(const char *url0, char *referer, void (*callback)(content_msg msg, struct content *c, void *p1, void *p2, const char *error), void *p1, void *p2, unsigned long width, unsigned long height, - bool only_2xx) + bool only_2xx, char *post_urlenc, + struct form_successful_control *post_multipart) { struct content *c; char *url = xstrdup(url0); @@ -67,7 +68,8 @@ struct content * fetchcache(const char *url0, char *referer, c->fetch_size = 0; c->width = width; c->height = height; - c->fetch = fetch_start(url, referer, fetchcache_callback, c, only_2xx); + c->fetch = fetch_start(url, referer, fetchcache_callback, c, only_2xx, + post_urlenc, post_multipart); free(url); if (c->fetch == 0) { LOG(("warning: fetch_start failed")); diff --git a/content/fetchcache.h b/content/fetchcache.h index bd7c09933..a0a25c2f8 100644 --- a/content/fetchcache.h +++ b/content/fetchcache.h @@ -18,10 +18,13 @@ #include #include "netsurf/content/content.h" +struct form_successful_control; + struct content * fetchcache(const char *url, char *referer, void (*callback)(content_msg msg, struct content *c, void *p1, void *p2, const char *error), void *p1, void *p2, unsigned long width, unsigned long height, - bool only_2xx); + bool only_2xx, char *post_urlenc, + struct form_successful_control *post_multipart); #endif diff --git a/css/css.c b/css/css.c index c5c5c7780..3dfcdd632 100644 --- a/css/css.c +++ b/css/css.c @@ -173,7 +173,7 @@ void css_revive(struct content *c, unsigned int width, unsigned int height) c->data.css.import_content[i] = fetchcache( c->data.css.import_url[i], c->url, css_atimport_callback, c, i, - c->width, c->height, true); + c->width, c->height, true, 0, 0); if (c->data.css.import_content[i] == 0) continue; if (c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) @@ -333,7 +333,7 @@ void css_atimport(struct content *c, struct css_node *node) c->data.css.import_url[i] = url_join(url, c->url); c->data.css.import_content[i] = fetchcache( c->data.css.import_url[i], c->url, css_atimport_callback, - c, i, c->width, c->height, true); + c, i, c->width, c->height, true, 0, 0); if (c->data.css.import_content[i] && c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) c->active++; @@ -381,7 +381,7 @@ void css_atimport_callback(content_msg msg, struct content *css, c->data.css.import_url[i] = xstrdup(error); c->data.css.import_content[i] = fetchcache( c->data.css.import_url[i], c->url, css_atimport_callback, - c, i, css->width, css->height, true); + c, i, css->width, css->height, true, 0, 0); if (c->data.css.import_content[i] && c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) c->active++; @@ -568,7 +568,7 @@ void css_parse_property_list(struct css_style * style, char * str) void *parser; YY_BUFFER_STATE buffer; int token; - struct parse_params param = {1, 0, 0}; + struct parse_params param = {1, 0, 0, false}; css_lex_init(&lexer); parser = css_parser_Alloc(malloc); diff --git a/debug/netsurfd.c b/debug/netsurfd.c index 3d4c1cb5b..c09dd3f2f 100644 --- a/debug/netsurfd.c +++ b/debug/netsurfd.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) return 0; url[strlen(url) - 1] = 0; destroyed = 0; - c = fetchcache(url, 0, callback, 0, 0, 100, 1000, false); + c = fetchcache(url, 0, callback, 0, 0, 100, 1000, false, 0, 0); if (c) { done = c->status == CONTENT_STATUS_DONE; while (!done) diff --git a/desktop/browser.c b/desktop/browser.c index 67a4670dc..16fc03126 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -38,6 +38,9 @@ static int redraw_box_list(struct browser_window* bw, struct box* current, static void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end); static void browser_window_follow_link(struct browser_window* bw, unsigned long click_x, unsigned long click_y, int click_type); +static void browser_window_open_location_post(struct browser_window* bw, + const char* url0, char *post_urlenc, + struct form_successful_control *post_multipart); static void browser_window_callback(content_msg msg, struct content *c, void *p1, void *p2, const char *error); static void download_window_callback(content_msg msg, struct content *c, @@ -117,7 +120,7 @@ void browser_window_back(struct browser_window* bw) if (bw->history->earlier != NULL) { bw->history = bw->history->earlier; - browser_window_open_location_historical(bw, bw->history->url); + browser_window_open_location_historical(bw, bw->history->url, 0, 0); } } } @@ -129,7 +132,7 @@ void browser_window_forward(struct browser_window* bw) if (bw->history->later != NULL) { bw->history = bw->history->later; - browser_window_open_location_historical(bw, bw->history->url); + browser_window_open_location_historical(bw, bw->history->url, 0, 0); } } } @@ -241,7 +244,9 @@ void browser_window_destroy(struct browser_window* bw) LOG(("end")); } -void browser_window_open_location_historical(struct browser_window* bw, const char* url) +void browser_window_open_location_historical(struct browser_window* bw, + const char* url, char *post_urlenc, + struct form_successful_control *post_multipart) { LOG(("bw = %p, url = %s", bw, url)); @@ -251,7 +256,8 @@ void browser_window_open_location_historical(struct browser_window* bw, const ch browser_window_start_throbber(bw); bw->time0 = clock(); bw->loading_content = fetchcache(url, 0, browser_window_callback, bw, 0, - gui_window_get_width(bw->window), 0, false); + gui_window_get_width(bw->window), 0, false, + post_urlenc, post_multipart); if (bw->loading_content == 0) { browser_window_set_status(bw, "Unable to fetch document"); return; @@ -265,12 +271,19 @@ void browser_window_open_location_historical(struct browser_window* bw, const ch } void browser_window_open_location(struct browser_window* bw, const char* url0) +{ + browser_window_open_location_post(bw, url0, 0, 0); +} + +void browser_window_open_location_post(struct browser_window* bw, + const char* url0, char *post_urlenc, + struct form_successful_control *post_multipart) { char *url; LOG(("bw = %p, url0 = %s", bw, url0)); assert(bw != 0 && url0 != 0); url = url_join(url0, bw->url); - browser_window_open_location_historical(bw, url); + browser_window_open_location_historical(bw, url, post_urlenc, post_multipart); /* TODO: move this to somewhere below CONTENT_MSG_READY below */ if (bw->history == NULL) bw->history = history_create(NULL, url); @@ -1569,36 +1582,41 @@ void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* } +/** + * Collect controls and submit a form. + */ + void browser_form_submit(struct browser_window *bw, struct form *form, struct form_control *submit_button) { + char *data, *url; struct form_successful_control *success; success = form_successful_controls(form, submit_button); - if (form->method == method_GET) { - /*GET request*/ - /*GET basically munges the entire form data - into one URL. */ - - char *data = form_url_encode(success); - char *url = xcalloc(1, strlen(form->action) + strlen(data) + 2); - sprintf(url, "%s?%s", form->action, data); - free(data); - browser_window_open_location(bw, url); - xfree(url); - - } else { - /*POST request*/ - assert(form->method == method_POST); - - LOG(("POST request - not implemented yet")); - - /*POST is a standard HTTP method. - Basically, it creates a new request - and sends the form data as the request - body.*/ - } + switch (form->method) { + case method_GET: + data = form_url_encode(success); + url = xcalloc(1, strlen(form->action) + strlen(data) + 2); + sprintf(url, "%s?%s", form->action, data); + free(data); + browser_window_open_location(bw, url); + free(url); + break; + + case method_POST_URLENC: + data = form_url_encode(success); + browser_window_open_location_post(bw, form->action, data, 0); + free(data); + break; + + case method_POST_MULTIPART: + browser_window_open_location_post(bw, form->action, 0, success); + break; + + default: + assert(0); + } form_free_successful(success); } diff --git a/desktop/browser.h b/desktop/browser.h index 38dc3628b..2afbd83bb 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -99,7 +99,9 @@ struct box_selection struct browser_window* create_browser_window(int flags, int width, int height); void browser_window_destroy(struct browser_window* bw); void browser_window_open_location(struct browser_window* bw, const char* url); -void browser_window_open_location_historical(struct browser_window* bw, const char* url); +void browser_window_open_location_historical(struct browser_window* bw, + const char* url, char *post_urlenc, + struct form_successful_control *post_multipart); int browser_window_action(struct browser_window* bw, struct browser_action* act); void browser_window_set_status(struct browser_window* bw, const char* text); diff --git a/render/box.c b/render/box.c index 3ad80ffad..6e9518931 100644 --- a/render/box.c +++ b/render/box.c @@ -14,7 +14,7 @@ #include #include #include "libxml/HTMLparser.h" -#include "netsurf/content/fetchcache.h" +#include "netsurf/content/content.h" #include "netsurf/css/css.h" #include "netsurf/render/box.h" #include "netsurf/render/font.h" @@ -737,22 +737,31 @@ struct result box_image(xmlNode *n, struct status *status, struct result box_form(xmlNode *n, struct status *status, struct css_style *style) { - char* s; + char *s, *s2; struct box *box; struct form *form; box = box_create(style, status->href, status->title); - status->current_form = form = xcalloc(1, sizeof(*form)); - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { - form->action = s; + s = (char *) xmlGetProp(n, (const xmlChar *) "action"); + if (!s) { + /* the action attribute is required */ + return (struct result) {box, 1}; } + status->current_form = form = xcalloc(1, sizeof(*form)); + form->action = s; + form->method = method_GET; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { - if (stricmp(s, "post") == 0) - form->method = method_POST; + if (strcasecmp(s, "post") == 0) { + form->method = method_POST_URLENC; + if ((s2 = (char *) xmlGetProp(n, (const xmlChar *) "enctype"))) { + if (strcasecmp(s2, "multipart/form-data") == 0) + form->method = method_POST_MULTIPART; + xmlFree(s2); + } + } xmlFree(s); } @@ -913,13 +922,18 @@ void add_option(xmlNode* n, struct form_control* current_select, char *text) current_select->data.select.last_item->next = option; current_select->data.select.last_item = option; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { + option->value = s; + } else { + option->value = xstrdup(text); + } + for (c = text; *c; c++) if (*c == ' ') *c = 160; option->selected = option->initial_selected = false; option->text = text; - option->value = 0; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "selected"))) { xmlFree(s); @@ -930,10 +944,6 @@ void add_option(xmlNode* n, struct form_control* current_select, char *text) current_select->data.select.current = option; } } - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { - option->value = s; - } } struct result box_input(xmlNode *n, struct status *status, diff --git a/render/form.c b/render/form.c index f4ed0a9f8..eade477ba 100644 --- a/render/form.c +++ b/render/form.c @@ -74,7 +74,7 @@ struct form_successful_control *form_successful_controls(struct form *form, if (control->type == GADGET_SELECT) { for (option = control->data.select.items; option; option = option->next) { - if (option->selected && option->value) { + if (option->selected) { success_new = xcalloc(1, sizeof(*success_new)); success_new->name = xstrdup(control->name); success_new->value = xstrdup(option->value); diff --git a/render/form.h b/render/form.h index b81abf01a..10e357ec7 100644 --- a/render/form.h +++ b/render/form.h @@ -14,15 +14,19 @@ #define _NETSURF_RENDER_FORM_H_ #include -#include "netsurf/render/box.h" +struct box; struct form_control; struct form_option; /** HTML form. */ struct form { - char *action; /* url */ - enum {method_GET, method_POST} method; + char *action; /**< Url to submit to. */ + enum { + method_GET, /**< GET, always url encoded. */ + method_POST_URLENC, /**< POST, url encoded. */ + method_POST_MULTIPART /**< POST, multipart/form-data. */ + } method; /**< Method and enctype. */ struct form_control *controls; /**< Linked list of controls. */ struct form_control *last_control; /**< Last control in list. */ }; diff --git a/render/html.c b/render/html.c index 0d868f996..e023de9e8 100644 --- a/render/html.c +++ b/render/html.c @@ -185,7 +185,7 @@ void html_convert_css_callback(content_msg msg, struct content *css, c->active--; c->data.html.stylesheet_content[i] = fetchcache( error, c->url, html_convert_css_callback, - c, i, css->width, css->height, true); + c, i, css->width, css->height, true, 0, 0); if (c->data.html.stylesheet_content[i] != 0 && c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE) c->active++; @@ -238,7 +238,7 @@ void html_find_stylesheets(struct content *c, xmlNode *head) #endif c->url, html_convert_css_callback, - c, 0, c->width, c->height, true); + c, 0, c->width, c->height, true, 0, 0); assert(c->data.html.stylesheet_content[0] != 0); if (c->data.html.stylesheet_content[0]->status != CONTENT_STATUS_DONE) c->active++; @@ -289,7 +289,7 @@ void html_find_stylesheets(struct content *c, xmlNode *head) (i + 1) * sizeof(*c->data.html.stylesheet_content)); c->data.html.stylesheet_content[i] = fetchcache(url, c->url, html_convert_css_callback, c, i, - c->width, c->height, true); + c->width, c->height, true, 0, 0); if (c->data.html.stylesheet_content[i] && c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE) c->active++; @@ -376,8 +376,8 @@ void html_fetch_object(struct content *c, char *url, struct box *box) /* start fetch */ c->data.html.object[i].content = fetchcache(url, c->url, html_object_callback, - c, i, - c->width, c->height, true); /* we don't know the object's + c, i, c->width, c->height, + true, 0, 0); /* we don't know the object's dimensions yet; use parent's as an estimate */ if (c->data.html.object[i].content) { @@ -467,7 +467,7 @@ void html_object_callback(content_msg msg, struct content *object, c->data.html.object[i].url = xstrdup(error); c->data.html.object[i].content = fetchcache( error, c->url, html_object_callback, - c, i, 0, 0, true); + c, i, 0, 0, true, 0, 0); if (c->data.html.object[i].content) { c->active++; if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE) @@ -556,7 +556,7 @@ void html_revive(struct content *c, unsigned int width, unsigned int height) c->data.html.object[i].content = fetchcache( c->data.html.object[i].url, c->url, html_object_callback, - c, i, 0, 0, true); + c, i, 0, 0, true, 0, 0); if (c->data.html.object[i].content && c->data.html.object[i].content->status != CONTENT_STATUS_DONE) c->active++; diff --git a/riscos/401login.c b/riscos/401login.c index 0ab0ffbea..edd081cc0 100644 --- a/riscos/401login.c +++ b/riscos/401login.c @@ -136,5 +136,5 @@ void do_thing() { break; } if (gw != NULL) - browser_window_open_location_historical(gw->data.browser.bw, url); + browser_window_open_location_historical(gw->data.browser.bw, url, 0, 0); } diff --git a/riscos/gui.c b/riscos/gui.c index 328d40691..3979fd691 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -732,7 +732,8 @@ void ro_gui_toolbar_click(gui_window* g, wimp_pointer* pointer) } else if (pointer->i == ro_theme_icon(current_theme, THEME_TOOLBAR, "TOOLBAR_RELOAD")) { - browser_window_open_location_historical(g->data.browser.bw, g->data.browser.bw->url); + browser_window_open_location_historical(g->data.browser.bw, + g->data.browser.bw->url, 0, 0); } } diff --git a/riscos/mouseactions.c b/riscos/mouseactions.c index 265465b5b..6c0bd6289 100644 --- a/riscos/mouseactions.c +++ b/riscos/mouseactions.c @@ -56,7 +56,7 @@ void ro_gui_mouse_action(gui_window *g) { case mouseaction_RELOAD: browser_window_open_location_historical(g->data.browser.bw, - g->data.browser.bw->url); + g->data.browser.bw->url, 0, 0); break; } } -- cgit v1.2.3