int server_partial_file_request(struct httpd *env, struct client *clt, char *path, struct stat *st, char *range_str) { struct http_descriptor *resp = clt->clt_descresp; struct http_descriptor *desc = clt->clt_descreq; struct media_type *media, multipart_media; struct range *range; struct evbuffer *evb = NULL; size_t content_length; int code = 500, fd = -1, i, nranges, ret; uint32_t boundary; char content_range[64]; const char *errstr = NULL; /* Ignore range request for methods other than GET */ if (desc->http_method != HTTP_METHOD_GET) return server_file_request(env, clt, path, st); if ((range = parse_range(range_str, st->st_size, &nranges)) == NULL) { code = 416; (void)snprintf(content_range, sizeof(content_range), "bytes */%lld", st->st_size); errstr = content_range; goto abort; } /* Now open the file, should be readable or we have another problem */ if ((fd = open(path, O_RDONLY)) == -1) goto abort; media = media_find(env->sc_mediatypes, path); if ((evb = evbuffer_new()) == NULL) { errstr = "failed to allocate file buffer"; goto abort; } if (nranges == 1) { (void)snprintf(content_range, sizeof(content_range), "bytes %lld-%lld/%lld", range->start, range->end, st->st_size); if (kv_add(&resp->http_headers, "Content-Range", content_range) == NULL) goto abort; content_length = range->end - range->start + 1; if (buffer_add_range(fd, evb, range) == 0) goto abort; } else { content_length = 0; boundary = arc4random(); /* Generate a multipart payload of byteranges */ while (nranges--) { if ((i = evbuffer_add_printf(evb, "\r\n--%ud\r\n", boundary)) == -1) goto abort; content_length += i; if ((i = evbuffer_add_printf(evb, "Content-Type: %s/%s\r\n", media == NULL ? "application" : media->media_type, media == NULL ? "octet-stream" : media->media_subtype)) == -1) goto abort; content_length += i; if ((i = evbuffer_add_printf(evb, "Content-Range: bytes %lld-%lld/%lld\r\n\r\n", range->start, range->end, st->st_size)) == -1) goto abort; content_length +=i; if (buffer_add_range(fd, evb, range) == 0) goto abort; content_length += range->end - range->start + 1; range++; } if ((i = evbuffer_add_printf(evb, "\r\n--%ud--\r\n", boundary)) == -1) goto abort; content_length += i; /* prepare multipart/byteranges media type */ (void)strlcpy(multipart_media.media_type, "multipart", sizeof(multipart_media.media_type)); (void)snprintf(multipart_media.media_subtype, sizeof(multipart_media.media_subtype), "byteranges; boundary=%ud", boundary); media = &multipart_media; } ret = server_response_http(clt, 206, media, content_length, MINIMUM(time(NULL), st->st_mtim.tv_sec)); switch (ret) { case -1: goto fail; case 0: /* Connection is already finished */ close(fd); evbuffer_free(evb); evb = NULL; goto done; default: break; } if (server_bufferevent_write_buffer(clt, evb) == -1) goto fail; evbuffer_free(evb); evb = NULL; bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); if (clt->clt_persist) clt->clt_toread = TOREAD_HTTP_HEADER; else clt->clt_toread = TOREAD_HTTP_NONE; clt->clt_done = 0; done: server_reset_http(clt); return (0); fail: bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE); bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, code, errstr); return (-1); }
int server_file_index(struct httpd *env, struct client *clt, struct stat *st) { char path[PATH_MAX]; char tmstr[21]; struct http_descriptor *desc = clt->clt_descreq; struct server_config *srv_conf = clt->clt_srv_conf; struct dirent **namelist, *dp; int namesize, i, ret, fd = -1, namewidth, skip; int code = 500; struct evbuffer *evb = NULL; struct media_type *media; const char *stripped, *style; char *escapeduri, *escapedhtml, *escapedpath; struct tm tm; time_t t, dir_mtime; if ((ret = server_file_method(clt)) != 0) { code = ret; goto abort; } /* Request path is already canonicalized */ stripped = server_root_strip(desc->http_path, srv_conf->strip); if ((size_t)snprintf(path, sizeof(path), "%s%s", srv_conf->root, stripped) >= sizeof(path)) goto abort; /* Now open the file, should be readable or we have another problem */ if ((fd = open(path, O_RDONLY)) == -1) goto abort; /* Save last modification time */ #if __FreeBSD_version < 900011 dir_mtime = MINIMUM(time(NULL), st->st_mtimespec.tv_sec); #else dir_mtime = MINIMUM(time(NULL), st->st_mtim.tv_sec); #endif if ((evb = evbuffer_new()) == NULL) goto abort; if ((namesize = scandir(path, &namelist, NULL, alphasort)) == -1) goto abort; /* Indicate failure but continue going through the list */ skip = 0; if ((escapedpath = escape_html(desc->http_path)) == NULL) goto fail; /* A CSS stylesheet allows minimal customization by the user */ style = "body { background-color: white; color: black; font-family: " "sans-serif; }\nhr { border: 0; border-bottom: 1px dashed; }\n"; /* Generate simple HTML index document */ if (evbuffer_add_printf(evb, "<!DOCTYPE html>\n" "<html>\n" "<head>\n" "<title>Index of %s</title>\n" "<style type=\"text/css\"><!--\n%s\n--></style>\n" "</head>\n" "<body>\n" "<h1>Index of %s</h1>\n" "<hr>\n<pre>\n", escapedpath, style, escapedpath) == -1) skip = 1; free(escapedpath); for (i = 0; i < namesize; i++) { dp = namelist[i]; if (skip || fstatat(fd, dp->d_name, st, 0) == -1) { free(dp); continue; } t = st->st_mtime; localtime_r(&t, &tm); strftime(tmstr, sizeof(tmstr), "%d-%h-%Y %R", &tm); namewidth = 51 - strlen(dp->d_name); if ((escapeduri = url_encode(dp->d_name)) == NULL) goto fail; if ((escapedhtml = escape_html(dp->d_name)) == NULL) goto fail; if (dp->d_name[0] == '.' && !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) { /* ignore hidden files starting with a dot */ } else if (S_ISDIR(st->st_mode)) { namewidth -= 1; /* trailing slash */ if (evbuffer_add_printf(evb, "<a href=\"%s%s/\">%s/</a>%*s%s%20s\n", strchr(escapeduri, ':') != NULL ? "./" : "", escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", tmstr, "-") == -1) skip = 1; } else if (S_ISREG(st->st_mode)) { if (evbuffer_add_printf(evb, "<a href=\"%s%s\">%s</a>%*s%s%20llu\n", strchr(escapeduri, ':') != NULL ? "./" : "", escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", tmstr, st->st_size) == -1) skip = 1; } free(escapeduri); free(escapedhtml); free(dp); } free(namelist); if (skip || evbuffer_add_printf(evb, "</pre>\n<hr>\n</body>\n</html>\n") == -1) goto abort; close(fd); fd = -1; media = media_find(env->sc_mediatypes, "index.html"); ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb), dir_mtime); switch (ret) { case -1: goto fail; case 0: /* Connection is already finished */ evbuffer_free(evb); goto done; default: break; } if (server_bufferevent_write_buffer(clt, evb) == -1) goto fail; evbuffer_free(evb); evb = NULL; bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); if (clt->clt_persist) clt->clt_toread = TOREAD_HTTP_HEADER; else clt->clt_toread = TOREAD_HTTP_NONE; clt->clt_done = 0; done: server_reset_http(clt); return (0); fail: bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE); bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: if (fd != -1) close(fd); if (evb != NULL) evbuffer_free(evb); server_abort_http(clt, code, desc->http_path); return (-1); }
void httpc_read_cb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; int dropped = 0; assert(client->state >= httpc_request_sent); redsocks_touch_client(client); if (client->state == httpc_request_sent) { size_t len = EVBUFFER_LENGTH(buffev->input); char *line = redsocks_evbuffer_readline(buffev->input); if (line) { unsigned int code; if (sscanf(line, "HTTP/%*u.%*u %u", &code) == 1) { // 1 == one _assigned_ match if (code == 407) { // auth failed http_auth *auth = (void*)(client->instance + 1); if (auth->last_auth_query != NULL && auth->last_auth_count == 1) { redsocks_log_error(client, LOG_NOTICE, "proxy auth failed"); redsocks_drop_client(client); dropped = 1; } else if (client->instance->config.login == NULL || client->instance->config.password == NULL) { redsocks_log_error(client, LOG_NOTICE, "proxy auth required, but no login information provided"); redsocks_drop_client(client); dropped = 1; } else { char *auth_request = get_auth_request_header(buffev->input); if (!auth_request) { redsocks_log_error(client, LOG_NOTICE, "403 found, but no proxy auth challenge"); redsocks_drop_client(client); dropped = 1; } else { free(line); free(auth->last_auth_query); char *ptr = auth_request; ptr += strlen(auth_request_header); while (isspace(*ptr)) ptr++; size_t last_auth_query_len = strlen(ptr) + 1; auth->last_auth_query = calloc(last_auth_query_len, 1); memcpy(auth->last_auth_query, ptr, last_auth_query_len); auth->last_auth_count = 0; free(auth_request); if (bufferevent_disable(client->relay, EV_WRITE)) { redsocks_log_errno(client, LOG_ERR, "bufferevent_disable"); return; } /* close relay tunnel */ redsocks_close(EVENT_FD(&client->relay->ev_write)); bufferevent_free(client->relay); /* set to initial state*/ client->state = httpc_new; /* and reconnect */ redsocks_connect_relay(client); return; } } } else if (200 <= code && code <= 299) { client->state = httpc_reply_came; } else { redsocks_log_error(client, LOG_NOTICE, "%s", line); redsocks_drop_client(client); dropped = 1; } } free(line); } else if (len >= HTTP_HEAD_WM_HIGH) { redsocks_drop_client(client); dropped = 1; } } if (dropped) return; while (client->state == httpc_reply_came) { char *line = redsocks_evbuffer_readline(buffev->input); if (line) { if (strlen(line) == 0) { client->state = httpc_headers_skipped; } free(line); } else { break; } } if (client->state == httpc_headers_skipped) { redsocks_start_relay(client); } }
int server_file_request(struct httpd *env, struct client *clt, char *path, struct stat *st) { struct server_config *srv_conf = clt->clt_srv_conf; struct media_type *media; const char *errstr = NULL; int fd = -1, ret, code = 500; if ((ret = server_file_method(clt)) != 0) { code = ret; goto abort; } if ((ret = server_file_modified_since(clt->clt_descreq, st)) != -1) return ret; /* Now open the file, should be readable or we have another problem */ if ((fd = open(path, O_RDONLY)) == -1) goto abort; media = media_find(env->sc_mediatypes, path); ret = server_response_http(clt, 200, media, st->st_size, #if __FreeBSD_version < 900011 MINIMUM(time(NULL), st->st_mtimespec.tv_sec)); #else MINIMUM(time(NULL), st->st_mtim.tv_sec)); #endif switch (ret) { case -1: goto fail; case 0: /* Connection is already finished */ close(fd); goto done; default: break; } clt->clt_fd = fd; if (clt->clt_srvbev != NULL) bufferevent_free(clt->clt_srvbev); clt->clt_srvbev = bufferevent_new(clt->clt_fd, server_read, server_write, server_file_error, clt); if (clt->clt_srvbev == NULL) { errstr = "failed to allocate file buffer event"; goto fail; } /* Adjust read watermark to the socket output buffer size */ bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0, clt->clt_sndbufsiz); bufferevent_settimeout(clt->clt_srvbev, srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec); bufferevent_enable(clt->clt_srvbev, EV_READ); bufferevent_disable(clt->clt_bev, EV_READ); done: server_reset_http(clt); return (0); fail: bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE); bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, code, errstr); return (-1); }
static void evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) { bufferevent_disable(evcon->bufev, EV_WRITE); }
static void socks_read_cb(struct bufferevent *bev, void *ptr) { obfsproxyssh_client_session_t *session = ptr; obfsproxyssh_t *state = session->client->state; struct evbuffer *buf; struct sockaddr_in addr; unsigned char *p, *userid; size_t len; int i; assert(bev == session->socks_ev); buf = bufferevent_get_input(bev); len = evbuffer_get_length(buf); if (len < SOCKS_4_CONNECT_REQUEST_LEN) return; p = evbuffer_pullup(buf, len); if (NULL == p) { log_f(state, "SOCKS: Error: %s Failed to pullup (OOM?)", bdata(session->socks_addr)); goto out_free; } /* * Parse the SOCKS 4 CONNECT * * uint8_4 VN -> 4 * uint8_t CN -> 1 * uint16_t DSTPORT * uint32_t DSTIP * uint8_t USERID[] (Tor PT arguments) * uint8_t NULL -> 0 */ if (SOCKS_4_VER != p[0]) { log_f(state, "SOCKS: Error: %s Invalid SOCKS protocol version %d", bdata(session->socks_addr), p[0]); goto out_free; } if (SOCKS_4_CMD_CONNECT != p[1]) { log_f(state, "SOCKS: Error: %s Invalid SOCKS 4 command %d", bdata(session->socks_addr), p[1]); goto out_free; } userid = p + SOCKS_4_CONNECT_REQUEST_LEN; for (i = 0; i < len - SOCKS_4_CONNECT_REQUEST_LEN; i++) { if ('\0' == userid[i]) { if (len != SOCKS_4_CONNECT_REQUEST_LEN + i + 1) { log_f(state, "SOCKS: Error: %s Trailing garbage after CONNECT", bdata(session->socks_addr)); goto out_free; } bufferevent_disable(bev, EV_READ); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = *(uint16_t *) (p + 2); addr.sin_addr.s_addr = *(uint32_t *) (p + 4); if (ssh_new_connection(session, &addr, (char *) userid)) goto out_free; evbuffer_drain(buf, len); return; } } if (len > OBFSPROXYSSH_CLIENT_MAX_SOCKS_REQ) { log_f(state, "SOCKS: Error: %s SOCKS 4 Request too big", bdata(session->socks_addr)); goto out_free; } return; out_free: session_free(session); return; }
/** Called on successful connections and errors */ void event_cb(struct bufferevent *bev, short e, void *data) { struct conn *c = data; uint32_t error_conditions = BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT; #if SSL_DEBUG_LEVEL > 1 errprintf(stdout, "ssl_slave: event callback triggered with flags 0x%hx\n", e); #endif if (e & BEV_EVENT_CONNECTED) { if (c->local_bev == bev) { local_connected(c); } else { ssl_connected(c); } } else if (e & BEV_EVENT_TIMEOUT) { if (c->state == C_SSL_CONNECTING) { /* Handshake timed out. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: SSL handshake timeout.\n"); #endif bufferevent_disable(c->remote_bev, EV_READ | EV_WRITE); bufferevent_free(c->remote_bev); c->remote_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->local_bev) { bufferevent_disable(c->local_bev, EV_READ); bufferevent_flush(c->local_bev, EV_WRITE, BEV_FINISHED); } delete_conn(c); } else { /* Bug in some versions of libevent cause this to trigger when it shouldn't. Ignore. */ return; } } else if (e & error_conditions) { if (c->local_bev == bev) { /* Mush side of the connection went away. Flush SSL buffer and shut down. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: Lost local connection. State: %d, reason 0x%hx.\n", c->state, e); #endif bufferevent_disable(c->local_bev, EV_READ | EV_WRITE); bufferevent_free(c->local_bev); c->local_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->remote_bev) { bufferevent_disable(c->remote_bev, EV_READ); bufferevent_flush(c->remote_bev, EV_WRITE, BEV_FINISHED); SSL_shutdown(bufferevent_openssl_get_ssl(c->remote_bev)); } delete_conn(c); } else { /* Remote side of the connection went away. Flush mush buffer and shut down. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: Lost SSL connection. State: %d, reason 0x%hx.\n", c->state, e); #endif bufferevent_disable(c->remote_bev, EV_READ | EV_WRITE); bufferevent_free(c->remote_bev); c->remote_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->local_bev) { bufferevent_disable(c->local_bev, EV_READ); bufferevent_flush(c->local_bev, EV_WRITE, BEV_FINISHED); } delete_conn(c); } } }
void test_bufferevent_zlib(void *arg) { struct bufferevent *bev1=NULL, *bev2=NULL; char buffer[8333]; z_stream z_input, z_output; int i, r; evutil_socket_t pair[2] = {-1, -1}; (void)arg; infilter_calls = outfilter_calls = readcb_finished = writecb_finished = errorcb_invoked = 0; if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { tt_abort_perror("socketpair"); } evutil_make_socket_nonblocking(pair[0]); evutil_make_socket_nonblocking(pair[1]); bev1 = bufferevent_socket_new(NULL, pair[0], 0); bev2 = bufferevent_socket_new(NULL, pair[1], 0); memset(&z_output, 0, sizeof(z_output)); r = deflateInit(&z_output, Z_DEFAULT_COMPRESSION); tt_int_op(r, ==, Z_OK); memset(&z_input, 0, sizeof(z_input)); r = inflateInit(&z_input); tt_int_op(r, ==, Z_OK); /* initialize filters */ bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter, BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, &z_output); bev2 = bufferevent_filter_new(bev2, zlib_input_filter, NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, &z_input); bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL); bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); bufferevent_disable(bev1, EV_READ); bufferevent_enable(bev1, EV_WRITE); bufferevent_enable(bev2, EV_READ); for (i = 0; i < (int)sizeof(buffer); i++) buffer[i] = i; /* break it up into multiple buffer chains */ bufferevent_write(bev1, buffer, 1800); bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800); /* we are done writing - we need to flush everything */ bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED); event_dispatch(); tt_want(infilter_calls); tt_want(outfilter_calls); tt_want(readcb_finished); tt_want(writecb_finished); tt_want(!errorcb_invoked); test_ok = 1; end: if (bev1) bufferevent_free(bev1); if (bev2) bufferevent_free(bev2); if (pair[0] >= 0) evutil_closesocket(pair[0]); if (pair[1] >= 0) evutil_closesocket(pair[1]); }
int server_fcgi(struct httpd *env, struct client *clt) { struct server_fcgi_param param; struct server_config *srv_conf = clt->clt_srv_conf; struct http_descriptor *desc = clt->clt_descreq; struct fcgi_record_header *h; struct fcgi_begin_request_body *begin; char hbuf[HOST_NAME_MAX+1]; size_t scriptlen; int pathlen; int fd = -1, ret; const char *stripped, *p, *alias, *errstr = NULL; char *str, *script = NULL; if (srv_conf->socket[0] == ':') { struct sockaddr_storage ss; in_port_t port; p = srv_conf->socket + 1; port = strtonum(p, 0, 0xffff, &errstr); if (errstr != NULL) { log_warn("%s: strtonum %s, %s", __func__, p, errstr); goto fail; } memset(&ss, 0, sizeof(ss)); ss.ss_family = AF_INET; ((struct sockaddr_in *) &ss)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); port = htons(port); if ((fd = server_socket_connect(&ss, port, srv_conf)) == -1) goto fail; } else { struct sockaddr_un sun; size_t len; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) goto fail; memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; len = strlcpy(sun.sun_path, srv_conf->socket, sizeof(sun.sun_path)); if (len >= sizeof(sun.sun_path)) { errstr = "socket path to long"; goto fail; } sun.sun_len = len; if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) goto fail; } socket_set_blockmode(fd, BM_NONBLOCK); memset(hbuf, 0, sizeof(hbuf)); clt->clt_fcgi_state = FCGI_READ_HEADER; clt->clt_fcgi_toread = sizeof(struct fcgi_record_header); if (clt->clt_srvevb != NULL) evbuffer_free(clt->clt_srvevb); clt->clt_srvevb = evbuffer_new(); if (clt->clt_srvevb == NULL) { errstr = "failed to allocate evbuffer"; goto fail; } close(clt->clt_fd); clt->clt_fd = fd; if (clt->clt_srvbev != NULL) bufferevent_free(clt->clt_srvbev); clt->clt_srvbev = bufferevent_new(fd, server_fcgi_read, NULL, server_file_error, clt); if (clt->clt_srvbev == NULL) { errstr = "failed to allocate fcgi buffer event"; goto fail; } memset(¶m, 0, sizeof(param)); h = (struct fcgi_record_header *)¶m.buf; h->version = 1; h->type = FCGI_BEGIN_REQUEST; h->id = htons(1); h->content_len = htons(sizeof(struct fcgi_begin_request_body)); h->padding_len = 0; begin = (struct fcgi_begin_request_body *)¶m.buf[sizeof(struct fcgi_record_header)]; begin->role = htons(FCGI_RESPONDER); bufferevent_write(clt->clt_srvbev, ¶m.buf, sizeof(struct fcgi_record_header) + sizeof(struct fcgi_begin_request_body)); h->type = FCGI_PARAMS; h->content_len = param.total_len = 0; alias = desc->http_path_alias != NULL ? desc->http_path_alias : desc->http_path; stripped = server_root_strip(alias, srv_conf->strip); if ((pathlen = asprintf(&script, "%s%s", srv_conf->root, stripped)) == -1) { errstr = "failed to get script name"; goto fail; } scriptlen = path_info(script); /* * no part of root should show up in PATH_INFO. * therefore scriptlen should be >= strlen(root) */ if (scriptlen < strlen(srv_conf->root)) scriptlen = strlen(srv_conf->root); if ((int)scriptlen < pathlen) { if (fcgi_add_param(¶m, "PATH_INFO", script + scriptlen, clt) == -1) { errstr = "failed to encode param"; goto fail; } script[scriptlen] = '\0'; } /* * calculate length of http SCRIPT_NAME: * add length of stripped prefix, * subtract length of prepended local root */ scriptlen += (stripped - alias) - strlen(srv_conf->root); if ((str = strndup(alias, scriptlen)) == NULL) goto fail; ret = fcgi_add_param(¶m, "SCRIPT_NAME", str, clt); free(str); if (ret == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SCRIPT_FILENAME", script, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (desc->http_query) if (fcgi_add_param(¶m, "QUERY_STRING", desc->http_query, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "DOCUMENT_ROOT", srv_conf->root, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "DOCUMENT_URI", alias, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "GATEWAY_INTERFACE", "CGI/1.1", clt) == -1) { errstr = "failed to encode param"; goto fail; } if (srv_conf->flags & SRVFLAG_AUTH) { if (fcgi_add_param(¶m, "REMOTE_USER", clt->clt_remote_user, clt) == -1) { errstr = "failed to encode param"; goto fail; } } /* Add HTTP_* headers */ if (server_headers(clt, desc, server_fcgi_writeheader, ¶m) == -1) { errstr = "failed to encode param"; goto fail; } if (srv_conf->flags & SRVFLAG_TLS) if (fcgi_add_param(¶m, "HTTPS", "on", clt) == -1) { errstr = "failed to encode param"; goto fail; } (void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf)); if (fcgi_add_param(¶m, "REMOTE_ADDR", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } (void)snprintf(hbuf, sizeof(hbuf), "%d", ntohs(clt->clt_port)); if (fcgi_add_param(¶m, "REMOTE_PORT", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "REQUEST_METHOD", server_httpmethod_byid(desc->http_method), clt) == -1) { errstr = "failed to encode param"; goto fail; } if (!desc->http_query) { if (fcgi_add_param(¶m, "REQUEST_URI", desc->http_path, clt) == -1) { errstr = "failed to encode param"; goto fail; } } else if (asprintf(&str, "%s?%s", desc->http_path, desc->http_query) != -1) { ret = fcgi_add_param(¶m, "REQUEST_URI", str, clt); free(str); if (ret == -1) { errstr = "failed to encode param"; goto fail; } } (void)print_host(&clt->clt_srv_ss, hbuf, sizeof(hbuf)); if (fcgi_add_param(¶m, "SERVER_ADDR", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } (void)snprintf(hbuf, sizeof(hbuf), "%d", ntohs(server_socket_getport(&clt->clt_srv_ss))); if (fcgi_add_param(¶m, "SERVER_PORT", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SERVER_NAME", srv_conf->name, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SERVER_PROTOCOL", desc->http_version, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SERVER_SOFTWARE", HTTPD_SERVERNAME, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (param.total_len != 0) { /* send last params record */ bufferevent_write(clt->clt_srvbev, ¶m.buf, sizeof(struct fcgi_record_header) + ntohs(h->content_len)); } /* send "no more params" message */ h->content_len = 0; bufferevent_write(clt->clt_srvbev, ¶m.buf, sizeof(struct fcgi_record_header)); bufferevent_settimeout(clt->clt_srvbev, srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec); bufferevent_enable(clt->clt_srvbev, EV_READ|EV_WRITE); if (clt->clt_toread != 0) { server_read_httpcontent(clt->clt_bev, clt); bufferevent_enable(clt->clt_bev, EV_READ); } else { bufferevent_disable(clt->clt_bev, EV_READ); fcgi_add_stdin(clt, NULL); } if (strcmp(desc->http_version, "HTTP/1.1") == 0) { clt->clt_fcgi_chunked = 1; } else { /* HTTP/1.0 does not support chunked encoding */ clt->clt_fcgi_chunked = 0; clt->clt_persist = 0; } clt->clt_fcgi_end = 0; clt->clt_done = 0; free(script); return (0); fail: free(script); if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, 500, errstr); return (-1); }
int BufferEvent::Disable(short ev_type) { return bufferevent_disable(bufev_, ev_type); }
/** * Link bufferevent with monitor connection. * @param[in] conn Monitor connection. * @param[in] bev Bufferevent instance. */ void zmonitor_conn_set_listener(struct zmonitor_conn *conn, struct bufferevent *bev) { bufferevent_disable(bev, EV_READ); bufferevent_setcb(bev, NULL, NULL, zmonitor_event_cb, conn); conn->bev = bev; }
int server_partial_file_request(struct httpd *env, struct client *clt, char *path, struct stat *st, char *range_str) { struct server_config *srv_conf = clt->clt_srv_conf; struct http_descriptor *resp = clt->clt_descresp; struct http_descriptor *desc = clt->clt_descreq; struct media_type *media, multipart_media; struct range_data *r = &clt->clt_ranges; struct range *range; size_t content_length = 0; int code = 500, fd = -1, i, nranges, ret; char content_range[64]; const char *errstr = NULL; /* Ignore range request for methods other than GET */ if (desc->http_method != HTTP_METHOD_GET) return server_file_request(env, clt, path, st); if ((nranges = parse_ranges(clt, range_str, st->st_size)) < 1) { code = 416; (void)snprintf(content_range, sizeof(content_range), "bytes */%lld", st->st_size); errstr = content_range; goto abort; } /* Now open the file, should be readable or we have another problem */ if ((fd = open(path, O_RDONLY)) == -1) goto abort; media = media_find_config(env, srv_conf, path); r->range_media = media; if (nranges == 1) { range = &r->range[0]; (void)snprintf(content_range, sizeof(content_range), "bytes %lld-%lld/%lld", range->start, range->end, st->st_size); if (kv_add(&resp->http_headers, "Content-Range", content_range) == NULL) goto abort; range = &r->range[0]; content_length += range->end - range->start + 1; } else { /* Add boundary, all parts will be handled by the callback */ arc4random_buf(&clt->clt_boundary, sizeof(clt->clt_boundary)); /* Calculate Content-Length of the complete multipart body */ for (i = 0; i < nranges; i++) { range = &r->range[i]; /* calculate Content-Length of the complete body */ if ((ret = snprintf(NULL, 0, "\r\n--%llu\r\n" "Content-Type: %s/%s\r\n" "Content-Range: bytes %lld-%lld/%lld\r\n\r\n", clt->clt_boundary, media->media_type, media->media_subtype, range->start, range->end, st->st_size)) < 0) goto abort; /* Add data length */ content_length += ret + range->end - range->start + 1; } if ((ret = snprintf(NULL, 0, "\r\n--%llu--\r\n", clt->clt_boundary)) < 0) goto abort; content_length += ret; /* prepare multipart/byteranges media type */ (void)strlcpy(multipart_media.media_type, "multipart", sizeof(multipart_media.media_type)); (void)snprintf(multipart_media.media_subtype, sizeof(multipart_media.media_subtype), "byteranges; boundary=%llu", clt->clt_boundary); media = &multipart_media; } /* Start with first range */ r->range_toread = TOREAD_HTTP_RANGE; ret = server_response_http(clt, 206, media, content_length, MINIMUM(time(NULL), st->st_mtim.tv_sec)); switch (ret) { case -1: goto fail; case 0: /* Connection is already finished */ close(fd); goto done; default: break; } clt->clt_fd = fd; if (clt->clt_srvbev != NULL) bufferevent_free(clt->clt_srvbev); clt->clt_srvbev_throttled = 0; clt->clt_srvbev = bufferevent_new(clt->clt_fd, server_read_httprange, server_write, server_file_error, clt); if (clt->clt_srvbev == NULL) { errstr = "failed to allocate file buffer event"; goto fail; } /* Adjust read watermark to the socket output buffer size */ bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0, clt->clt_sndbufsiz); bufferevent_settimeout(clt->clt_srvbev, srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec); bufferevent_enable(clt->clt_srvbev, EV_READ); bufferevent_disable(clt->clt_bev, EV_READ); done: server_reset_http(clt); return (0); fail: bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE); bufferevent_free(clt->clt_bev); clt->clt_bev = NULL; abort: if (fd != -1) close(fd); if (errstr == NULL) errstr = strerror(errno); server_abort_http(clt, code, errstr); return (-1); }
/** HTTP request callback */ static void http_request_cb(struct evhttp_request* req, void* arg) { // Disable reading to work around a libevent bug, fixed in 2.2.0. if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { evhttp_connection* conn = evhttp_request_get_connection(req); if (conn) { bufferevent* bev = evhttp_connection_get_bufferevent(conn); if (bev) { bufferevent_disable(bev, EV_READ); } } } std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req)); // Early address-based allow check if (!ClientAllowed(hreq->GetPeer())) { LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n", hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_FORBIDDEN); return; } // Early reject unknown HTTP methods if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) { LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n", hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_BADMETHOD); return; } LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n", RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString()); // Find registered handler for prefix std::string strURI = hreq->GetURI(); std::string path; std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin(); std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end(); for (; i != iend; ++i) { bool match = false; if (i->exactMatch) match = (strURI == i->prefix); else match = (strURI.substr(0, i->prefix.size()) == i->prefix); if (match) { path = strURI.substr(i->prefix.size()); break; } } // Dispatch to worker thread if (i != iend) { std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler)); assert(workQueue); if (workQueue->Enqueue(item.get())) item.release(); /* if true, queue took ownership */ else { LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n"); item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded"); } } else { hreq->WriteReply(HTTP_NOTFOUND); } }
static void __out_start(struct chunk_transfer_s *ct) { gint64 header_size = 0; int dst_fd; struct evkeyval *kv; struct evkeyvalq *src; GSList *dsts_out = NULL; /* struct evbuffer */ GSList *lc = NULL; GSList *lb = NULL; struct timeval tv_read, tv_write; GSList *l = NULL; if (chunk_transfer_get_dst_status(ct) != CNX_NONE) return; GRID_DEBUG("Starting the output..."); const char *content_length = chunk_transfer_find_req_header(ct, "Content-Length"); ct->dst_size = ct->dst_size_remaining = g_ascii_strtoll(content_length, NULL, 10); if(chunk_transfer_get_target_rawx_count(ct) < 1) { GRID_ERROR("ERROR, no destination rawx..."); return; } GRID_DEBUG("ok we have targets, prepare to send data"); for(l = ct->dst_rawx; l && l->data; l = l->next) { gchar dst[128]; gchar port_str[16]; guint16 port = 0; struct bufferevent* bevent = NULL; addr_info_get_addr(&(((service_info_t*)l->data)->addr), dst, sizeof(dst), &port); bzero(port_str, sizeof(port_str)); g_snprintf(port_str, sizeof(port_str), "%d", port); GRID_DEBUG("addr extracted: %s %s", dst, port_str); dst_fd = tcpip_open(dst, port_str); GRID_DEBUG("Destination opened"); /* ***** */ bevent = bufferevent_socket_new(ct->evt_base, dst_fd, 0); GRID_DEBUG("buffer event created"); tv_write.tv_sec = 3; tv_write.tv_usec = 0; tv_read.tv_sec = 3; tv_read.tv_usec = 0; bufferevent_set_timeouts(bevent, &tv_read, &tv_write); bufferevent_setcb(bevent, __dst_cb_in, __dst_cb_out, __dst_cb_error, ct); bufferevent_disable(bevent, EV_READ|EV_WRITE); /* Write the HTTP request and the grid headers */ /* WARN: don't do prepend if you want to keep all in good order !! */ dsts_out = g_slist_append(dsts_out, bufferevent_get_output(bevent)); ct->dst_bevents = g_slist_append(ct->dst_bevents, bevent); } if(ct->dst_chunks) { GRID_DEBUG("dst_chunks filled, its ok"); } else { GRID_DEBUG("no dst_chunks defined"); } for (lc = ct->dst_chunks, lb = dsts_out; lc && lc->data && lb && lb->data; lc = lc->next, lb = lb->next) { gchar idstr[65]; bzero(idstr, sizeof(idstr)); container_id_to_string(lc->data, idstr, sizeof(idstr)); evbuffer_add_printf(lb->data, "PUT /%s HTTP/1.0\r\n", idstr); GRID_DEBUG("Sending put order"); /* Add missing headers (xattr not returned by rawx) */ evbuffer_add_printf(lb->data, "chunkid: %s\n", idstr); evbuffer_add_printf(lb->data, "chunkpos: %"G_GUINT32_FORMAT"\n", ct->source_chunk->position); evbuffer_add_printf(lb->data, "chunksize: %"G_GINT64_FORMAT"\n", ct->source_chunk->size); /* container id str */ gchar cidstr[65]; bzero(cidstr, sizeof(cidstr)); container_id_t cid; chunk_transfer_get_container_id(ct, cid); container_id_to_string(cid, cidstr, sizeof(cidstr)); evbuffer_add_printf(lb->data, "containerid: %s\n", cidstr); evbuffer_add_printf(lb->data, "contentpath: %s\n", chunk_transfer_get_content_path(ct)); evbuffer_add_printf(lb->data, "chunknb: %"G_GUINT32_FORMAT"\n", chunk_transfer_get_content_nb_chunks(ct)); evbuffer_add_printf(lb->data, "contentsize: %"G_GINT64_FORMAT"\n", chunk_transfer_get_content_size(ct)); if(ct->attrs->usr_metadata) evbuffer_add_printf(lb->data, "contentmetadata: %s\n", ct->attrs->usr_metadata); if(ct->attrs->sys_metadata) evbuffer_add_printf(lb->data, "contentmetadata-sys: %s\n", ct->attrs->sys_metadata); /* **** */ evbuffer_add_printf(lb->data, "Connection: close\r\n"); evbuffer_add_printf(lb->data, "Content-Type: application/octet-stream\r\n"); evbuffer_add_printf(lb->data, "Content-Length: %"G_GINT64_FORMAT"\r\n", ct->dst_size); } src = ct->src_req->input_headers; TAILQ_FOREACH(kv, src, next) { GRID_DEBUG("headers found : %s | %s", kv->key, kv->value); if (g_str_has_prefix(kv->key, "X-Grid-") || g_str_has_prefix(kv->key, "container") || g_str_has_prefix(kv->key, "content") || g_str_has_prefix(kv->key, "chunk")) { for(lb = dsts_out; lb && lb->data; lb = lb->next) { evbuffer_add_printf(lb->data, "%s: %s\r\n", kv->key, kv->value); } } }
static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; _bufferevent_incref_and_lock(bufev); if (event == EV_TIMEOUT) { what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* we somehow lowered the watermark, stop reading */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } readmax = _bufferevent_get_read_max(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; _bufferevent_decrement_read_buckets(bufev_p, res); /* Invoke the user callback - must always be called last */ if (evbuffer_get_length(input) >= bufev->wm_read.low) _bufferevent_run_readcb(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); _bufferevent_run_eventcb(bufev, what); done: _bufferevent_decref_and_unlock(bufev); }
void Connection::disable() { m_socket->shutdown(); bufferevent_disable( m_handle, EV_READ | EV_WRITE ); }
static void bufferevent_writecb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); int res = 0; short what = BEV_EVENT_WRITING; int connected = 0; ev_ssize_t atmost = -1; _bufferevent_incref_and_lock(bufev); if (event == EV_TIMEOUT) { what |= BEV_EVENT_TIMEOUT; goto error; } if (bufev_p->connecting) { int c = evutil_socket_finished_connecting(fd); /* we need to fake the error if the connection was refused * immediately - usually connection to localhost on BSD */ if (bufev_p->connection_refused) { bufev_p->connection_refused = 0; c = -1; } if (c == 0) goto done; bufev_p->connecting = 0; if (c < 0) { event_del(&bufev->ev_write); event_del(&bufev->ev_read); _bufferevent_run_eventcb(bufev, BEV_EVENT_ERROR); goto done; } else { connected = 1; #ifdef _WIN32 if (BEV_IS_ASYNC(bufev)) { event_del(&bufev->ev_write); bufferevent_async_set_connected(bufev); _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); goto done; } #endif _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); if (!(bufev->enabled & EV_WRITE) || bufev_p->write_suspended) { event_del(&bufev->ev_write); goto done; } } } atmost = _bufferevent_get_write_max(bufev_p); if (bufev_p->write_suspended) goto done; if (evbuffer_get_length(bufev->output)) { evbuffer_unfreeze(bufev->output, 1); res = evbuffer_write_atmost(bufev->output, fd, atmost); evbuffer_freeze(bufev->output, 1); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case XXXX Actually, a 0 on write doesn't indicate an EOF. An ECONNRESET might be more typical. */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; _bufferevent_decrement_write_buckets(bufev_p, res); } if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } /* * Invoke the user callback if our buffer is drained or below the * low watermark. */ if ((res || !connected) && evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { _bufferevent_run_writecb(bufev); } goto done; reschedule: if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } goto done; error: bufferevent_disable(bufev, EV_WRITE); _bufferevent_run_eventcb(bufev, what); done: _bufferevent_decref_and_unlock(bufev); }
static void cb_write(struct bufferevent *bev, void *arg) { verbose(FIREHOSE, "%s(): Write exhausted\n", __func__); bufferevent_disable(bev, EV_WRITE); bufferevent_enable(bev, EV_READ); }
// This starts a new TCP/TLS connection to notblocked // It is called both when a new local proxy connection is accepted // and when we need to re-open an existing telex transport (state->local is reused) void make_new_telex_conn(struct telex_state *state) { struct telex_conf *conf = state->conf; HexDump(LOG_TRACE, state->name, "Opening telex id:", state->remote_conn_id, sizeof(state->remote_conn_id)); state->remotetcp = bufferevent_socket_new(state->base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!state->remotetcp) { LogError(state->name, "Could not create remote bufferevent socket"); StateCleanup(&state); return; } _inc(BEV); // TODO: make nonblocking lookup? bufferevent_socket_connect_hostname(state->remotetcp, NULL, AF_INET, conf->notblocked_host, conf->notblocked_port); // After resolution... /* struct sockaddr_in sin; if (getpeername(bufferevent_getfd(state->remotetcp), (struct sockaddr *)&sin, (socklen_t*)sizeof(sin)) < 0) { perror("getpeername"); LogError("proxy", "getpeername failed"); StateCleanup(&state); return; } char ip_p[INET_ADDRSTRLEN]; LogTrace(state->name, "Connecting to %s:%d", evutil_inet_ntop(AF_INET, server_ip, ip_p, sizeof(ip_p)), state->conf->notblocked_port); //bufferevent_socket_connect(state->remotetcp, ai->ai_addr, (int)ai->ai_addrlen); */ if (ssl_new_telex(state) < 0) { ssl_log_errors(LOG_ERROR, state->name); LogError(state->name, "Could not create new telex SSL connection object"); StateCleanup(&state); return; } _inc(SSL); state->remote = bufferevent_openssl_filter_new(state->base, state->remotetcp, state->ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); // Not BEV_OPT_CLOSE_ON_FREE! if (!state->remote) { LogError(state->name, "Could not create remote SSL bufferevent filter"); StateCleanup(&state); return; } _inc(BEV); // First, set our read_cb to something that receives the SPTelex init message bufferevent_setcb(state->remote, (bufferevent_data_cb)first_read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Disable until SPTelex init msg bufferevent_disable(state->local, EV_READ|EV_WRITE); bufferevent_setcb(state->local, (bufferevent_data_cb)read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Hmm...we should make a second one of these state->in_local = 0; }
static void httpc_read_cb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; assert(client->relay == buffev); assert(client->state == httpc_request_sent || client->state == httpc_reply_came); redsocks_touch_client(client); // evbuffer_add() triggers callbacks, so we can't write to client->client // till we know that we're going to ONFAIL_FORWARD_HTTP_ERR. // And the decision is made when all the headers are processed. struct evbuffer* tee = NULL; const bool do_errtee = client->instance->config.on_proxy_fail == ONFAIL_FORWARD_HTTP_ERR; if (client->state == httpc_request_sent) { size_t len = evbuffer_get_length(buffev->input); char *line = redsocks_evbuffer_readline(buffev->input); if (line) { unsigned int code; if (sscanf(line, "HTTP/%*u.%*u %u", &code) == 1) { // 1 == one _assigned_ match if (code == 407) { // auth failed http_auth *auth = red_http_auth(client->instance); if (auth->last_auth_query != NULL && auth->last_auth_count == 1) { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy auth failed: %s", line); client->state = httpc_no_way; } else if (client->instance->config.login == NULL || client->instance->config.password == NULL) { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy auth required, but no login/password configured: %s", line); client->state = httpc_no_way; } else { if (do_errtee) tee = evbuffer_new(); char *auth_request = http_auth_request_header(buffev->input, tee); if (!auth_request) { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy auth required, but no <%s> header found: %s", auth_request_header, line); client->state = httpc_no_way; } else { free(line); if (tee) evbuffer_free(tee); free(auth->last_auth_query); char *ptr = auth_request; ptr += strlen(auth_request_header); while (isspace(*ptr)) ptr++; size_t last_auth_query_len = strlen(ptr) + 1; auth->last_auth_query = calloc(last_auth_query_len, 1); memcpy(auth->last_auth_query, ptr, last_auth_query_len); auth->last_auth_count = 0; free(auth_request); if (bufferevent_disable(client->relay, EV_WRITE)) { redsocks_log_errno(client, LOG_ERR, "bufferevent_disable"); return; } /* close relay tunnel */ redsocks_bufferevent_free(client->relay); /* set to initial state*/ client->state = httpc_new; /* and reconnect */ redsocks_connect_relay(client); return; } } } else if (200 <= code && code <= 299) { client->state = httpc_reply_came; } else { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy error: %s", line); client->state = httpc_no_way; } } else { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy bad firstline: %s", line); client->state = httpc_no_way; } if (do_errtee && client->state == httpc_no_way) { if (bufferevent_write(client->client, line, strlen(line)) != 0 || bufferevent_write(client->client, "\r\n", 2) != 0) { redsocks_log_errno(client, LOG_NOTICE, "bufferevent_write"); goto fail; } } free(line); } else if (len >= HTTP_HEAD_WM_HIGH) { redsocks_log_error(client, LOG_NOTICE, "HTTP Proxy reply is too long, %zu bytes", len); client->state = httpc_no_way; } } if (do_errtee && client->state == httpc_no_way) { if (tee) { if (bufferevent_write_buffer(client->client, tee) != 0) { redsocks_log_errno(client, LOG_NOTICE, "bufferevent_write_buffer"); goto fail; } } redsocks_shutdown(client, client->client, SHUT_RD); const size_t avail = evbuffer_get_length(client->client->input); if (avail) { if (evbuffer_drain(client->client->input, avail) != 0) { redsocks_log_errno(client, LOG_NOTICE, "evbuffer_drain"); goto fail; } } redsocks_shutdown(client, client->relay, SHUT_WR); client->state = httpc_headers_skipped; } fail: if (tee) { evbuffer_free(tee); } if (client->state == httpc_no_way) { redsocks_drop_client(client); return; } while (client->state == httpc_reply_came) { char *line = redsocks_evbuffer_readline(buffev->input); if (line) { if (strlen(line) == 0) { client->state = httpc_headers_skipped; } free(line); } else { break; } } if (client->state == httpc_headers_skipped) { redsocks_start_relay(client); } }
/** * @brief pauses a connection (disables reading) * * @param c a evhtp_connection_t * structure */ void evhtp_connection_pause(evhtp_connection_t * c) { if ((bufferevent_get_enabled(c->bev) & EV_READ)) { bufferevent_disable(c->bev, EV_READ); } }