📄 form.c
字号:
foreachback (sub, *list) if (list_has_next(*list, sub)) if (sub->next->position < sub->position) { next = sub->next; del_from_list(sub); add_at_pos(next, sub); sub = next; changed = 1; } } while (changed);}static voidget_successful_controls(struct document_view *doc_view, struct form_control *fc, struct list_head *list){ struct form_control *fc2; assert(doc_view && fc && fc->form && list); if_assert_failed return; foreach (fc2, fc->form->items) { if (((fc2->type != FC_SUBMIT && fc2->type != FC_IMAGE && fc2->type != FC_RESET && fc2->type != FC_BUTTON) || fc2 == fc) && fc2->name && fc2->name[0]) { struct form_state *fs = find_form_state(doc_view, fc2); if (!fs) continue; add_submitted_value_to_list(fc2, fs, list); } } sort_submitted_values(list);}static voidencode_controls(struct list_head *l, struct string *data, int cp_from, int cp_to){ struct submitted_value *sv; struct conv_table *convert_table = NULL; int lst = 0; assert(l && data); if_assert_failed return; foreach (sv, *l) { unsigned char *p2 = NULL; if (lst) add_char_to_string(data, '&'); else lst = 1; encode_uri_string(data, sv->name, 1); add_char_to_string(data, '='); /* Convert back to original encoding (see html_form_control() * for the original recoding). */ if (sv->type == FC_TEXTAREA) { unsigned char *p; p = encode_textarea(sv); if (p) { if (!convert_table) convert_table = get_translation_table(cp_from, cp_to); p2 = convert_string(convert_table, p, strlen(p), CSM_FORM, NULL, NULL, NULL); mem_free(p); } } else if (sv->type == FC_TEXT || sv->type == FC_PASSWORD) { if (!convert_table) convert_table = get_translation_table(cp_from, cp_to); p2 = convert_string(convert_table, sv->value, strlen(sv->value), CSM_FORM, NULL, NULL, NULL); } else { p2 = stracpy(sv->value); } if (p2) { encode_uri_string(data, p2, 1); mem_free(p2); } }}#define BOUNDARY_LENGTH 32#define realloc_bound_ptrs(bptrs, bptrs_size) \ mem_align_alloc(bptrs, bptrs_size, bptrs_size + 1, int, 0xFF)struct boundary_info { int count; int *offsets; unsigned char string[BOUNDARY_LENGTH];};static inline voidinit_boundary(struct boundary_info *boundary){ memset(boundary, 0, sizeof(*boundary)); memset(boundary->string, '0', BOUNDARY_LENGTH);}/* Add boundary to string and save the offset */static inline voidadd_boundary(struct string *data, struct boundary_info *boundary){ add_to_string(data, "--"); if (realloc_bound_ptrs(&boundary->offsets, boundary->count)) boundary->offsets[boundary->count++] = data->length; add_bytes_to_string(data, boundary->string, BOUNDARY_LENGTH);}static inline unsigned char *increment_boundary_counter(struct boundary_info *boundary){ int j; /* This is just a decimal string incrementation */ for (j = BOUNDARY_LENGTH - 1; j >= 0; j--) { if (boundary->string[j]++ < '9') return boundary->string; boundary->string[j] = '0'; } INTERNAL("Form data boundary counter overflow"); return NULL;}static inline voidcheck_boundary(struct string *data, struct boundary_info *boundary){ unsigned char *bound = boundary->string; int i; /* Search between all boundaries. There is a starting and an ending * boundary so only check the range of chars after the current offset * and before the next offset. If some string in the form data matches * the boundary string it is changed. */ for (i = 0; i < boundary->count - 1; i++) { /* Start after the boundary string and also jump past the * "\r\nContent-Disposition: form-data; name=\"" string added * before any form data. */ int start_offset = boundary->offsets[i] + BOUNDARY_LENGTH + 40; /* End so that there is atleast BOUNDARY_LENGTH chars to * compare. Subtract 2 char because there is no need to also * compare the '--' prefix that is part of the boundary. */ int end_offset = boundary->offsets[i + 1] - BOUNDARY_LENGTH - 2; unsigned char *pos = data->source + start_offset; unsigned char *end = data->source + end_offset; for (; pos <= end; pos++) { if (memcmp(pos, bound, BOUNDARY_LENGTH)) continue; /* If incrementing causes overflow bail out. There is * no need to reset the boundary string with '0' since * that is already done when incrementing. */ if (!increment_boundary_counter(boundary)) return; /* Else start checking all boundaries using the new * boundary string */ i = 0; break; } } /* Now update all the boundaries with the unique boundary string */ for (i = 0; i < boundary->count; i++) memcpy(data->source + boundary->offsets[i], bound, BOUNDARY_LENGTH);}/* FIXME: shouldn't we encode data at send time (in http.c) ? --Zas */static voidencode_multipart(struct session *ses, struct list_head *l, struct string *data, struct boundary_info *boundary, int cp_from, int cp_to){ struct conv_table *convert_table = NULL; struct submitted_value *sv; assert(ses && l && data && boundary); if_assert_failed return; init_boundary(boundary); foreach (sv, *l) { add_boundary(data, boundary); add_crlf_to_string(data); /* FIXME: name is not encoded. * from RFC 1867: * multipart/form-data contains a series of parts. * Each part is expected to contain a content-disposition * header where the value is "form-data" and a name attribute * specifies the field name within the form, * e.g., 'content-disposition: form-data; name="xxxxx"', * where xxxxx is the field name corresponding to that field. * Field names originally in non-ASCII character sets may be * encoded using the method outlined in RFC 1522. */ add_to_string(data, "Content-Disposition: form-data; name=\""); add_to_string(data, sv->name); add_char_to_string(data, '"'); if (sv->type == FC_FILE) {#define F_BUFLEN 1024 int fh, rd; unsigned char buffer[F_BUFLEN]; unsigned char *extension; add_to_string(data, "; filename=\""); add_to_string(data, get_filename_position(sv->value)); /* It sends bad data if the file name contains ", but Netscape does the same */ /* FIXME: We should follow RFCs 1522, 1867, * 2047 (updated by rfc 2231), to provide correct support * for non-ASCII and special characters in values. --Zas */ add_char_to_string(data, '"'); /* Add a Content-Type header if the type is configured */ extension = strrchr(sv->value, '.'); if (extension) { unsigned char *type = get_extension_content_type(extension); if (type) { add_crlf_to_string(data); add_to_string(data, "Content-Type: "); add_to_string(data, type); mem_free(type); } } add_crlf_to_string(data); add_crlf_to_string(data); if (*sv->value) { unsigned char *filename; if (get_cmd_opt_bool("anonymous")) { errno = EPERM; goto encode_error; } /* FIXME: DO NOT COPY FILE IN MEMORY !! --Zas */ filename = expand_tilde(sv->value); if (!filename) goto encode_error; fh = open(filename, O_RDONLY); mem_free(filename); if (fh == -1) goto encode_error; set_bin(fh); do { rd = safe_read(fh, buffer, F_BUFLEN); if (rd == -1) { close(fh); goto encode_error; } if (rd) add_bytes_to_string(data, buffer, rd); } while (rd); close(fh); }#undef F_BUFLEN } else { add_crlf_to_string(data); add_crlf_to_string(data); /* Convert back to original encoding (see * html_form_control() for the original recoding). */ if (sv->type == FC_TEXT || sv->type == FC_PASSWORD || sv->type == FC_TEXTAREA) { unsigned char *p; if (!convert_table) convert_table = get_translation_table(cp_from, cp_to); p = convert_string(convert_table, sv->value, strlen(sv->value), CSM_FORM, NULL, NULL, NULL); if (p) { add_to_string(data, p); mem_free(p); } } else { add_to_string(data, sv->value); } } add_crlf_to_string(data); } /* End-boundary */ add_boundary(data, boundary); add_to_string(data, "--\r\n"); check_boundary(data, boundary); mem_free_if(boundary->offsets); return;encode_error: mem_free_if(boundary->offsets); done_string(data); /* XXX: This error message should move elsewhere. --Zas */ info_box(ses->tab->term, MSGBOX_FREE_TEXT, N_("Error while posting form"), ALIGN_CENTER, msg_text(ses->tab->term, N_("Could not load file %s: %s"), sv->value, strerror(errno)));}static voidencode_newlines(struct string *string, unsigned char *data){ for (; *data; data++) { if (*data == '\n' || *data == '\r') { unsigned char buffer[3]; /* Hex it. */ buffer[0] = '%'; buffer[1] = hx((((int) *data) & 0xF0) >> 4); buffer[2] = hx(((int) *data) & 0xF); add_bytes_to_string(string, buffer, 3); } else { add_char_to_string(string, *data); } }}static voidencode_text_plain(struct list_head *l, struct string *data, int cp_from, int cp_to){ struct submitted_value *sv; struct conv_table *convert_table = get_translation_table(cp_from, cp_to); assert(l && data); if_assert_failed return; foreach (sv, *l) { unsigned char *area51 = NULL; unsigned char *value = sv->value; add_to_string(data, sv->name); add_char_to_string(data, '='); switch (sv->type) { case FC_TEXTAREA: value = area51 = encode_textarea(sv); if (!area51) break; /* Fall through */ case FC_TEXT: case FC_PASSWORD: /* Convert back to original encoding (see * html_form_control() for the original recoding). */ value = convert_string(convert_table, value, strlen(value), CSM_FORM, NULL, NULL, NULL); default: /* Falling right through to free that textarea stuff */ mem_free_if(area51); /* Did the conversion fail? */ if (!value) break; encode_newlines(data, value); /* Free if we did convert something */ if (value != sv->value) mem_free(value); } add_crlf_to_string(data); }}voiddo_reset_form(struct document_view *doc_view, struct form *form){ struct form_control *fc; assert(doc_view && doc_view->document); if_assert_failed return; foreach (fc, form->items) { struct form_state *fs = find_form_state(doc_view, fc); if (fs) init_form_state(fc, fs); }}enum frame_event_statusreset_form(struct session *ses, struct document_view *doc_view, int a){ struct link *link = get_current_link(doc_view); if (!link) return FRAME_EVENT_OK; do_reset_form(doc_view, get_link_form_control(link)->form); draw_forms(ses->tab->term, doc_view); /* Could be the refresh return value and then ditch the draw_forms() * call. */ return FRAME_EVENT_OK;}struct uri *get_form_uri(struct session *ses, struct document_view *doc_view, struct form_control *fc){ struct boundary_info boundary; INIT_LIST_HEAD(submit); struct string data; struct string go; int cp_from, cp_to; struct uri *uri; struct form *form; assert(ses && ses->tab && ses->tab->term); if_assert_failed return NULL; assert(doc_view && doc_view->document && fc && fc->form); if_assert_failed return NULL; form = fc->form; if (fc->type == FC_RESET) { do_reset_form(doc_view, form); return NULL; } else if (fc->type == FC_BUTTON) { return NULL; } if (!form->action || !init_string(&data)) return NULL; get_successful_controls(doc_view, fc, &submit); cp_from = get_opt_codepage_tree(ses->tab->term->spec, "charset"); cp_to = doc_view->document->cp; switch (form->method) { case FORM_METHOD_GET: case FORM_METHOD_POST: encode_controls(&submit, &data, cp_from, cp_to); break; case FORM_METHOD_POST_MP: encode_multipart(ses, &submit, &data, &boundary, cp_from, cp_to); break; case FORM_METHOD_POST_TEXT_PLAIN: encode_text_plain(&submit, &data, cp_from, cp_to); }#ifdef CONFIG_FORMHIST /* XXX: We check data.source here because a NULL value can indicate * not only a memory allocation failure, but also an error reading * a file that is to be uploaded. TODO: Distinguish between * these two classes of errors (is it worth it?). -- Miciah */ if (data.source && get_opt_bool("document.browse.forms.show_formhist")) memorize_form(ses, &submit, form);#endif done_submitted_value_list(&submit); if (!data.source || !init_string(&go)) { done_string(&data); return NULL; } switch (form->method) { case FORM_METHOD_GET: { unsigned char *pos = strchr(form->action, '#'); if (pos) { add_bytes_to_string(&go, form->action, pos - form->action); } else { add_to_string(&go, form->action); } if (strchr(go.source, '?')) add_char_to_string(&go, '&'); else add_char_to_string(&go, '?'); add_string_to_string(&go, &data); if (pos) add_to_string(&go, pos); break; } case FORM_METHOD_POST: case FORM_METHOD_POST_MP: case FORM_METHOD_POST_TEXT_PLAIN: { /* Note that we end content type here by a simple '\n', * replaced later by correct '\r\n' in http_send_header(). */ int i; add_to_string(&go, form->action); add_char_to_string(&go, POST_CHAR); if (form->method == FORM_METHOD_POST) { add_to_string(&go, "application/x-www-form-urlencoded\n"); } else if (form->method == FORM_METHOD_POST_TEXT_PLAIN) { /* Dunno about this one but we don't want the full * hextcat thingy. --jonas */ add_to_string(&go, "text/plain\n"); add_to_string(&go, data.source); break; } else { add_to_string(&go, "multipart/form-data; boundary="); add_bytes_to_string(&go, boundary.string, BOUNDARY_LENGTH); add_char_to_string(&go, '\n'); } for (i = 0; i < data.length; i++) { unsigned char p[3];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -