⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ne_request.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 3 页
字号:
	SOCK_ERR(req, ne_sock_readline(req->session->socket, req->respbuf, 				       sizeof req->respbuf),		 _("Could not read interim response headers"));	NE_DEBUG(NE_DBG_HTTP, "[discard] < %s", req->respbuf);    } while (strcmp(req->respbuf, EOL) != 0);    return NE_OK;}/* Send the request, and read the response Status-Line. Returns: *   NE_RETRY   connection closed by server; persistent connection *		timeout *   NE_OK	success *   NE_*	error * On NE_RETRY and NE_* responses, the connection will have been  * closed already. */static int send_request(ne_request *req, const ne_buffer *request){    ne_session *sess = req->session;    ssize_t ret = NE_OK;    int sentbody = 0; /* zero until body has been sent. */    int retry; /* non-zero whilst the request should be retried */    ne_status *status = &req->status;    /* Send the Request-Line and headers */    NE_DEBUG(NE_DBG_HTTP, "Sending request-line and headers:\n");    /* Open the connection if necessary */    HTTP_ERR(open_connection(req));    /* Allow retry if a persistent connection has been used. */    retry = sess->persisted;        ret = ne_sock_fullwrite(req->session->socket, request->data, 			    ne_buffer_size(request));    if (ret < 0) {	int aret = aborted(req, _("Could not send request"), ret);	return RETRY_RET(retry, ret, aret);    }        if (!req->use_expect100 && req->body_size > 0) {	/* Send request body, if not using 100-continue. */	ret = send_request_body(req);	if (ret < 0) {	    int aret = aborted(req, _("Could not send request body"), ret);	    return RETRY_RET(sess, ret, aret);	}    }        NE_DEBUG(NE_DBG_HTTP, "Request sent; retry is %d.\n", retry);    /* Loop eating interim 1xx responses (RFC2616 says these MAY be     * sent by the server, even if 100-continue is not used). */    while ((ret = read_status_line(req, status, retry)) == NE_OK 	   && status->klass == 1) {	NE_DEBUG(NE_DBG_HTTP, "Interim %d response.\n", status->code);	retry = 0; /* successful read() => never retry now. */	/* Discard headers with the interim response. */	if ((ret = discard_headers(req)) != NE_OK) break;	if (req->use_expect100 && (status->code == 100) && !sentbody) {	    /* Send the body after receiving the first 100 Continue */	    if ((ret = send_request_body(req)) != NE_OK) break;	    	    sentbody = 1;	}    }    return ret;}/* Read a message header from sock into buf, which has size 'buflen'. * * Returns: *   NE_RETRY: Success, read a header into buf. *   NE_OK: End of headers reached. *   NE_ERROR: Error (session error is set). */static int read_message_header(ne_request *req, char *buf, size_t buflen){    ssize_t n;    ne_socket *sock = req->session->socket;    n = ne_sock_readline(sock, buf, buflen);    if (n <= 0)	return aborted(req, _("Error reading response headers"), n);    NE_DEBUG(NE_DBG_HTTP, "[hdr] %s", buf);    strip_eol(buf, &n);    if (n == 0) {	NE_DEBUG(NE_DBG_HTTP, "End of headers.\n");	return NE_OK;    }    buf += n;    buflen -= n;    while (buflen > 0) {	char ch;	/* Collect any extra lines into buffer */	SOCK_ERR(req, ne_sock_peek(sock, &ch, 1),		 _("Error reading response headers"));	if (ch != ' ' && ch != '\t') {	    /* No continuation of this header: stop reading. */	    return NE_RETRY;	}	/* Otherwise, read the next line onto the end of 'buf'. */	n = ne_sock_readline(sock, buf, buflen);	if (n <= 0) {	    return aborted(req, _("Error reading response headers"), n);	}	NE_DEBUG(NE_DBG_HTTP, "[cont] %s", buf);	strip_eol(buf, &n);		/* assert(buf[0] == ch), which implies len(buf) > 0.	 * Otherwise the TCP stack is lying, but we'll be paranoid.	 * This might be a \t, so replace it with a space to be	 * friendly to applications (2616 says we MAY do this). */	if (n) buf[0] = ' ';	/* ready for the next header. */	buf += n;	buflen -= n;    }    ne_set_error(req->session, _("Response header too long"));    return NE_ERROR;}/* Apache's default is 100, seems reasonable. */#define MAX_HEADER_FIELDS 100/* Read response headers.  Returns NE_* code, sets session error. */static int read_response_headers(ne_request *req) {    char hdr[8192]; /* max header length */    int ret, count = 0;        while ((ret = read_message_header(req, hdr, sizeof hdr)) == NE_RETRY 	   && ++count < MAX_HEADER_FIELDS) {	struct header_handler *hdl;	char *pnt;	unsigned int hash = 0;		for (hdl = req->header_catchers; hdl != NULL; hdl = hdl->next)	    hdl->handler(hdl->userdata, hdr);	/* Strip any trailing whitespace */	pnt = hdr + strlen(hdr) - 1;	while (pnt > hdr && (*pnt == ' ' || *pnt == '\t'))	    *pnt-- = '\0';	/* Convert the header name to lower case and hash it. */	for (pnt = hdr; (*pnt != '\0' && *pnt != ':' && 			 *pnt != ' ' && *pnt != '\t'); pnt++) {	    *pnt = tolower(*pnt);	    hash = HH_ITERATE(hash,*pnt);	}	/* Skip over any whitespace before the colon. */	while (*pnt == ' ' || *pnt == '\t')	    *pnt++ = '\0';	/* ignore header lines which lack a ':'. */	if (*pnt != ':')	    continue;		/* NUL-terminate at the colon (when no whitespace before) */	*pnt++ = '\0';	/* Skip any whitespace after the colon... */	while (*pnt == ' ' || *pnt == '\t')	    pnt++;	/* pnt now points to the header value. */	NE_DEBUG(NE_DBG_HTTP, "Header Name: [%s], Value: [%s]\n", hdr, pnt);		/* Iterate through the header handlers */	for (hdl = req->header_handlers[hash]; hdl != NULL; hdl = hdl->next) {	    if (strcmp(hdr, hdl->name) == 0)		hdl->handler(hdl->userdata, pnt);	}    }    if (count == MAX_HEADER_FIELDS)	ret = aborted(	    req, _("Response exceeded maximum number of header fields."), 0);    return ret;}static int lookup_host(ne_session *sess, struct host_info *info){    NE_DEBUG(NE_DBG_HTTP, "Doing DNS lookup on %s...\n", info->hostname);    if (sess->notify_cb)	sess->notify_cb(sess->notify_ud, ne_conn_namelookup, info->hostname);    info->address = ne_addr_resolve(info->hostname, 0);    if (ne_addr_result(info->address)) {	char buf[256];	ne_set_error(sess, _("Could not resolve hostname `%s': %s"), 		     info->hostname,		     ne_addr_error(info->address, buf, sizeof buf));	ne_addr_destroy(info->address);	info->address = NULL;	return NE_LOOKUP;    } else {	return NE_OK;    }}int ne_begin_request(ne_request *req){    struct body_reader *rdr;    struct host_info *host;    ne_buffer *data;    const ne_status *const st = &req->status;    int ret;    /* Resolve hostname if necessary. */    host = req->session->use_proxy?&req->session->proxy:&req->session->server;    if (host->address == NULL)	HTTP_ERR(lookup_host(req->session, host));    req->resp.mode = R_TILLEOF;        /* FIXME: Determine whether to use the Expect: 100-continue header. */    req->use_expect100 = (req->session->expect100_works > -1) &&	(req->body_size > HTTP_EXPECT_MINSIZE) && req->session->is_http11;    /* Build the request string, and send it */    data = build_request(req);    DEBUG_DUMP_REQUEST(data->data);    ret = send_request(req, data);    /* Retry this once after a persistent connection timeout. */    if (ret == NE_RETRY && !req->session->no_persist) {	NE_DEBUG(NE_DBG_HTTP, "Persistent connection timed out, retrying.\n");	ret = send_request(req, data);    }    ne_buffer_destroy(data);    if (ret != NE_OK) return ret;    /* Determine whether server claims HTTP/1.1 compliance. */    req->session->is_http11 = (st->major_version == 1 &&                                st->minor_version > 0) || st->major_version > 1;    /* Persistent connections supported implicitly in HTTP/1.1 */    if (req->session->is_http11) req->can_persist = 1;    ne_set_error(req->session, "%d %s", st->code, st->reason_phrase);    /* Read the headers */    HTTP_ERR(read_response_headers(req));#ifdef NEON_SSL    /* Special case for CONNECT handling: the response has no body,     * and the connection can persist. */    if (req->session->in_connect && st->klass == 2) {	req->resp.mode = R_NO_BODY;	req->can_persist = 1;    }#endif    /* HEAD requests and 204, 205, 304 responses have no response body,     * regardless of what headers are present. */    if (req->method_is_head || st->code==204 || st->code==205 || st->code==304)    	req->resp.mode = R_NO_BODY;    /* Prepare for reading the response entity-body.  Call each of the     * body readers and ask them whether they want to accept this     * response or not. */    for (rdr = req->body_readers; rdr != NULL; rdr=rdr->next) {	rdr->use = rdr->accept_response(rdr->userdata, req, st);    }        req->resp.left = req->resp.length;    req->resp.chunk_left = 0;    return NE_OK;}int ne_end_request(ne_request *req){    struct hook *hk;    int ret = NE_OK;    /* Read headers in chunked trailers */    if (req->resp.mode == R_CHUNKED)	HTTP_ERR(read_response_headers(req));        NE_DEBUG(NE_DBG_HTTP, "Running post_send hooks\n");    for (hk = req->session->post_send_hooks; 	 ret == NE_OK && hk != NULL; hk = hk->next) {	ne_post_send_fn fn = (ne_post_send_fn)hk->fn;	ret = fn(req, hk->userdata, &req->status);    }        /* Close the connection if persistent connections are disabled or     * not supported by the server. */    if (req->session->no_persist || !req->can_persist)	ne_close_connection(req->session);    else	req->session->persisted = 1;        return ret;}int ne_request_dispatch(ne_request *req) {    int ret;    /* Loop sending the request:     * Retry whilst authentication fails and we supply it. */        do {	ssize_t len;		HTTP_ERR(ne_begin_request(req));		do {	    len = ne_read_response_block(req, req->respbuf,					 sizeof req->respbuf);	} while (len > 0);	if (len < 0) {	    return NE_ERROR;	}	ret = ne_end_request(req);    } while (ret == NE_RETRY);    NE_DEBUG(NE_DBG_HTTP | NE_DBG_FLUSH, 	   "Request ends, status %d class %dxx, error line:\n%s\n", 	   req->status.code, req->status.klass, req->session->error);    return ret;}const ne_status *ne_get_status(const ne_request *req){    return &req->status;}ne_session *ne_get_session(const ne_request *req){    return req->session;}#ifdef NEON_SSL/* Create a CONNECT tunnel through the proxy server. * Returns HTTP_* */static int proxy_tunnel(ne_session *sess){    /* Hack up an HTTP CONNECT request... */    ne_request *req;    int ret = NE_OK;    char ruri[200];    /* Can't use server.hostport here; Request-URI must include `:port' */    ne_snprintf(ruri, sizeof ruri, "%s:%u", sess->server.hostname,  		sess->server.port);    req = ne_request_create(sess, "CONNECT", ruri);    sess->in_connect = 1;    ret = ne_request_dispatch(req);    sess->in_connect = 0;    sess->persisted = 0; /* don't treat this is a persistent connection. */    if (ret != NE_OK || !sess->connected || req->status.klass != 2) {	ne_set_error	    (sess, _("Could not create SSL connection through proxy server"));	ret = NE_ERROR;    }    ne_request_destroy(req);    return ret;}#endif/* Make new TCP connection to server at 'host' of type 'name'.  Note * that once a connection to a particular network address has * succeeded, that address will be used first for the next attempt to * connect. *//* TODO: an alternate implementation could always cycle through the * addresses: this could ease server load, but could hurt SSL session * caching for SSL sessions, which would increase server load. */static int do_connect(ne_request *req, struct host_info *host, const char *err){    ne_session *const sess = req->session;    int ret;    if ((sess->socket = ne_sock_create()) == NULL) {        ne_set_error(sess, _("Could not create socket"));        return NE_ERROR;    }    if (host->current == NULL)	host->current = ne_addr_first(host->address);    do {	notify_status(sess, ne_conn_connecting, host->hostport);#ifdef NE_DEBUGGING	if (ne_debug_mask & NE_DBG_HTTP) {	    char buf[150];	    NE_DEBUG(NE_DBG_HTTP, "Connecting to %s\n",		     ne_iaddr_print(host->current, buf, sizeof buf));	}#endif	ret = ne_sock_connect(sess->socket, host->current, host->port);    } while (ret && /* try the next address... */	     (host->current = ne_addr_next(host->address)) != NULL);    if (ret) {        ne_set_error(sess, "%s: %s", err, ne_sock_error(sess->socket));        ne_sock_close(sess->socket);	return NE_CONNECT;    }    notify_status(sess, ne_conn_connected, sess->proxy.hostport);        if (sess->rdtimeout)	ne_sock_read_timeout(sess->socket, sess->rdtimeout);    sess->connected = 1;    /* clear persistent connection flag. */    sess->persisted = 0;    return NE_OK;}static int open_connection(ne_request *req) {    ne_session *sess = req->session;    int ret;        if (sess->connected) return NE_OK;    if (!sess->use_proxy)	ret = do_connect(req, &sess->server, _("Could not connect to server"));    else	ret = do_connect(req, &sess->proxy,			 _("Could not connect to proxy server"));    if (ret != NE_OK) return ret;#ifdef NEON_SSL    /* Negotiate SSL layer if required. */    if (sess->use_ssl && !sess->in_connect) {        /* CONNECT tunnel */        if (req->session->use_proxy)            ret = proxy_tunnel(sess);                if (ret == NE_OK)            ret = ne_negotiate_ssl(req);        /* This is probably only really needed for ne_negotiate_ssl         * failures as proxy_tunnel will fail via aborted(). */        if (ret != NE_OK)            ne_close_connection(sess);    }#endif        return ret;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -