static enum evhook_status script_hook_goto_url(va_list ap, void *data) { unsigned char **url = va_arg(ap, unsigned char **); struct session *ses = va_arg(ap, struct session *); int error; VALUE args[2]; VALUE result; if (*url == NULL) return EVENT_HOOK_STATUS_NEXT; args[0] = rb_str_new(*url, strlen((const char *)*url)); if (!ses || !have_location(ses)) { args[1] = Qnil; } else { args[1] = rb_str_new(struri(cur_loc(ses)->vs.uri), strlen((const char *)struri(cur_loc(ses)->vs.uri))); } result = erb_protected_method_call("goto_url_hook", 2, args, &error); if (error) { erb_report_error(ses, error); return EVENT_HOOK_STATUS_NEXT; } switch (rb_type(result)) { case T_STRING: { unsigned char *new_url; new_url = memacpy(RSTRING(result)->ptr, RSTRING(result)->len); if (new_url) { mem_free_set(url, new_url); } break; } case T_NIL: break; default: alert_ruby_error(ses, "goto_url_hook must return a string or nil"); } return EVENT_HOOK_STATUS_NEXT; }
static enum listbox_match match_cache_entry(struct listbox_item *item, struct terminal *term, unsigned char *text) { struct cache_entry *cached = item->udata; if (c_strcasestr(struri(cached->uri), text) || (cached->head && c_strcasestr(cached->head, text))) return LISTBOX_MATCH_OK; return LISTBOX_MATCH_NO; }
static void add_nntp_html_line(struct string *html, struct connection *conn, unsigned char *line) { struct nntp_connection_info *nntp = conn->info; switch (nntp->target) { case NNTP_TARGET_ARTICLE_NUMBER: case NNTP_TARGET_MESSAGE_ID: case NNTP_TARGET_GROUP_MESSAGE_ID: add_html_to_string(html, line, strlen(line)); break; case NNTP_TARGET_ARTICLE_RANGE: case NNTP_TARGET_GROUP: case NNTP_TARGET_GROUPS: { unsigned char *field = line; line = strchr((const char *)line, '\t'); if (!line) field = ""; else *line++ = 0; add_format_to_string(html, "<li value=\"%s\"><a href=\"%s/%s\">", field, struri(conn->uri), field); field = line; line = strchr((const char *)line, '\t'); if (line) *line++ = 0; add_header_to_string(html, field); add_to_string(html, "</a> "); if (line) { field = line; line = strchr((const char *)line, '\t'); if (line) *line++ = 0; add_header_to_string(html, field); } add_to_string(html, "</li>"); break; } case NNTP_TARGET_QUIT: break; } add_char_to_string(html, '\n'); }
static enum evhook_status script_hook_pre_format_html(va_list ap, void *data) { struct session *ses = va_arg(ap, struct session *); struct cache_entry *cached = va_arg(ap, struct cache_entry *); struct fragment *fragment = get_cache_fragment(cached); unsigned char *url = struri(cached->uri); if (my_perl && ses && url && cached->length && *fragment->data) do_script_hook_pre_format_html(url, cached, fragment); return EVENT_HOOK_STATUS_NEXT; }
static enum evhook_status script_hook_pre_format_html(va_list ap, void *data) { struct session *ses = va_arg(ap, struct session *); struct cache_entry *cached = va_arg(ap, struct cache_entry *); struct fragment *fragment = get_cache_fragment(cached); unsigned char *url = struri(cached->uri); int error; VALUE args[2]; VALUE result; evhook_use_params(ses && cached); if (!cached->length || !*fragment->data) return EVENT_HOOK_STATUS_NEXT; args[0] = rb_str_new2(url); args[1] = rb_str_new(fragment->data, fragment->length); result = erb_protected_method_call("pre_format_html_hook", 2, args, &error); if (error) { erb_report_error(ses, error); return EVENT_HOOK_STATUS_NEXT; } switch (rb_type(result)) { case T_STRING: { int len = RSTRING(result)->len; add_fragment(cached, 0, RSTRING(result)->ptr, len); normalize_cache_entry(cached, len); break; } case T_NIL: break; default: alert_ruby_error(ses, "pre_format_html_hook must return a string or nil"); } return EVENT_HOOK_STATUS_NEXT; }
static inline void do_script_hook_goto_url(struct session *ses, unsigned char **url) { int count; dSP; /* Keep in variables declaration block. */ ENTER; SAVETMPS; PUSHMARK(SP); my_XPUSHs(*url, strlen((const char *)*url)); if (!ses || !have_location(ses)) { XPUSHs(sv_2mortal(newSV(0))); } else { unsigned char *uri = struri(cur_loc(ses)->vs.uri); my_XPUSHs(uri, strlen((const char *)uri)); } PUTBACK; count = call_pv("goto_url_hook", G_EVAL | G_SCALAR); if (SvTRUE(ERRSV)) count = 0; /* FIXME: error message ? */ SPAGAIN; if (count == 1) { #ifndef CONFIG_PERL_POPPX_WITHOUT_N_A STRLEN n_a; /* Used by POPpx macro. */ #endif unsigned char *new_url = POPpx; if (new_url) { unsigned char *n = stracpy(new_url); if (n) { mem_free_set(url, n); } } } PUTBACK; FREETMPS; LEAVE; }
struct uri * get_proxy_uri(struct uri *uri, struct connection_state *error_state) { if (uri->protocol == PROTOCOL_PROXY) { return get_composed_uri(uri, URI_BASE); } else { #ifdef CONFIG_SCRIPTING unsigned char *tmp = NULL; static int get_proxy_event_id = EVENT_NONE; set_event_id(get_proxy_event_id, "get-proxy"); trigger_event(get_proxy_event_id, &tmp, struri(uri)); uri = get_proxy_worker(uri, tmp, error_state); mem_free_if(tmp); return uri; #else return get_proxy_worker(uri, NULL, error_state); #endif } }
enum uri_errno parse_uri(struct uri *uri, unsigned char *uristring) { unsigned char *prefix_end, *host_end; #ifdef CONFIG_IPV6 unsigned char *lbracket, *rbracket; #endif assertm(uristring != NULL, "No uri to parse."); memset(uri, 0, sizeof(*uri)); /* Nothing to do for an empty url. */ if_assert_failed return 0; if (!*uristring) return URI_ERRNO_EMPTY; uri->string = uristring; uri->protocollen = get_protocol_length(uristring); /* Invalid */ if (!uri->protocollen) return URI_ERRNO_INVALID_PROTOCOL; /* Figure out whether the protocol is known */ uri->protocol = get_protocol(struri(uri), uri->protocollen); prefix_end = uristring + uri->protocollen; /* ':' */ /* Check if there's a digit after the protocol name. */ if (isdigit(*prefix_end)) { uri->ip_family = uristring[uri->protocollen] - '0'; prefix_end++; } if (*prefix_end != ':') return URI_ERRNO_INVALID_PROTOCOL; prefix_end++; /* Skip slashes */ if (prefix_end[0] == '/' && prefix_end[1] == '/') { if (prefix_end[2] == '/' && get_protocol_need_slash_after_host(uri->protocol)) return URI_ERRNO_TOO_MANY_SLASHES; prefix_end += 2; } else if (get_protocol_need_slashes(uri->protocol)) { return URI_ERRNO_NO_SLASHES; } if (get_protocol_free_syntax(uri->protocol)) { uri->data = prefix_end; uri->datalen = strlen(prefix_end); return URI_ERRNO_OK; } else if (uri->protocol == PROTOCOL_FILE) { int datalen = strcspn(prefix_end, "#" POST_CHAR_S); unsigned char *frag_or_post = prefix_end + datalen; /* Extract the fragment part. */ if (datalen >= 0) { if (*frag_or_post == '#') { uri->fragment = frag_or_post + 1; uri->fragmentlen = strcspn(uri->fragment, POST_CHAR_S); frag_or_post = uri->fragment + uri->fragmentlen; } if (*frag_or_post == POST_CHAR) { uri->post = frag_or_post + 1; } } else { datalen = strlen(prefix_end); } /* A bit of a special case, but using the "normal" host * parsing seems a bit scary at this point. (see bug 107). */ if (datalen > 9 && !c_strncasecmp(prefix_end, "localhost/", 10)) { prefix_end += 9; datalen -= 9; } uri->data = prefix_end; uri->datalen = datalen; return URI_ERRNO_OK; } /* Isolate host */ #ifdef CONFIG_IPV6 /* Get brackets enclosing IPv6 address */ lbracket = strchr((const char *)prefix_end, '['); if (lbracket) { rbracket = strchr((const char *)lbracket, ']'); /* [address] is handled only inside of hostname part (surprisingly). */ if (rbracket && rbracket < prefix_end + strcspn(prefix_end, "/")) uri->ipv6 = 1; else lbracket = rbracket = NULL; } else { rbracket = NULL; } #endif /* Possibly skip auth part */ host_end = prefix_end + strcspn(prefix_end, "@"); if (prefix_end + strcspn(prefix_end, "/") > host_end && *host_end) { /* we have auth info here */ unsigned char *user_end; /* Allow '@' in the password component */ while (strcspn(host_end + 1, "@") < strcspn(host_end + 1, "/?")) host_end = host_end + 1 + strcspn(host_end + 1, "@"); user_end = strchr((const char *)prefix_end, ':'); if (!user_end || user_end > host_end) { uri->user = prefix_end; uri->userlen = host_end - prefix_end; } else { uri->user = prefix_end; uri->userlen = user_end - prefix_end; uri->password = user_end + 1; uri->passwordlen = host_end - user_end - 1; } prefix_end = host_end + 1; } #ifdef CONFIG_IPV6 if (uri->ipv6) host_end = rbracket + strcspn(rbracket, ":/?"); else #endif host_end = prefix_end + strcspn(prefix_end, ":/?"); #ifdef CONFIG_IPV6 if (uri->ipv6) { int addrlen = rbracket - lbracket - 1; /* Check for valid length. * addrlen >= sizeof(hostbuf) is theorically impossible * but i keep the test in case of... Safer, imho --Zas */ assertm(addrlen >= 0 && addrlen < NI_MAXHOST, "parse_uri(): addrlen value is bad (%d) for URL '%s'. " "Problems are likely to be encountered. Please report " "this, it is a security bug!", addrlen, uristring); if_assert_failed return URI_ERRNO_IPV6_SECURITY; uri->host = lbracket + 1; uri->hostlen = addrlen; } else
/* @cache_entry_class.getProperty */ static JSBool cache_entry_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) { struct cache_entry *cached; JSBool ret; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) return JS_FALSE; cached = JS_GetInstancePrivate(ctx, obj, (JSClass *) &cache_entry_class, NULL); if (!cached) return JS_FALSE; /* already detached */ assert(cache_entry_is_valid(cached)); if_assert_failed return JS_FALSE; /* Get a strong reference to the cache entry to prevent it * from being deleted if some function called below decides to * collect garbage. After this, all code paths must * eventually unlock the object. */ object_lock(cached); undef_to_jsval(ctx, vp); if (!JSID_IS_INT(id)) ret = JS_FALSE; else switch (JSID_TO_INT(id)) { case CACHE_ENTRY_CONTENT: { struct fragment *fragment = get_cache_fragment(cached); if (!fragment) { ret = JS_FALSE; break; } *vp = STRING_TO_JSVAL(JS_NewStringCopyN(smjs_ctx, fragment->data, fragment->length)); ret = JS_TRUE; break; } case CACHE_ENTRY_TYPE: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->content_type)); ret = JS_TRUE; break; case CACHE_ENTRY_HEAD: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->head)); ret = JS_TRUE; break; case CACHE_ENTRY_LENGTH: *vp = INT_TO_JSVAL(cached->length); ret = JS_TRUE; break; case CACHE_ENTRY_URI: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, struri(cached->uri))); ret = JS_TRUE; break; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case * and leave *@vp unchanged. Do the same here. * (Actually not quite the same, as we already used * @undef_to_jsval.) */ ret = JS_TRUE; break; } object_unlock(cached); return ret; }