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

📄 ne_request.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 3 页
字号:
int ne_accept_always(void *userdata, ne_request *req, const ne_status *st){    return 1;}				   int ne_accept_2xx(void *userdata, ne_request *req, const ne_status *st){    return (st->klass == 2);}/* Handler for the "Transfer-Encoding" response header: treat *any* * such header as implying a chunked response, per the "Protocol * Compliance" statement in the manual. */static void te_hdr_handler(void *userdata, const char *value) {    struct ne_response *resp = userdata;    resp->mode = R_CHUNKED;    }/* Handler for the "Connection" response header */static void connection_hdr_handler(void *userdata, const char *value){    ne_request *req = userdata;    if (strcasecmp(value, "close") == 0) {	req->can_persist = 0;    } else if (strcasecmp(value, "Keep-Alive") == 0) {	req->can_persist = 1;    }}static void clength_hdr_handler(void *userdata, const char *value){    struct ne_response *resp = userdata;    size_t len = strtoul(value, NULL, 10);    if (len != ULONG_MAX && resp->mode == R_TILLEOF) {	resp->mode = R_CLENGTH;	resp->length = len;    }}ne_request *ne_request_create(ne_session *sess,			      const char *method, const char *path) {    ne_request *req = ne_calloc(sizeof *req);    NE_DEBUG(NE_DBG_HTTP, "Creating request...\n");    req->session = sess;    req->headers = ne_buffer_create();    /* Add in the fixed headers */    add_fixed_headers(req);    /* Set the standard stuff */    req->method = ne_strdup(method);    req->method_is_head = (strcmp(method, "HEAD") == 0);    /* Add in handlers for all the standard HTTP headers. */    ne_add_response_header_handler(req, "Content-Length", 				   clength_hdr_handler, &req->resp);    ne_add_response_header_handler(req, "Transfer-Encoding", 				   te_hdr_handler, &req->resp);    ne_add_response_header_handler(req, "Connection", 				   connection_hdr_handler, req);    /* Only use an absoluteURI here when absolutely necessary: some     * servers can't parse them. */    if (req->session->use_proxy && !req->session->use_ssl && path[0] == '/')	req->uri = ne_concat(req->session->scheme, "://", 			     req->session->server.hostport, path, NULL);    else	req->uri = ne_strdup(path);    {	struct hook *hk;	NE_DEBUG(NE_DBG_HTTP, "Running request create hooks.\n");	for (hk = sess->create_req_hooks; hk != NULL; hk = hk->next) {	    ne_create_request_fn fn = (ne_create_request_fn)hk->fn;	    fn(req, hk->userdata, method, req->uri);	}    }    NE_DEBUG(NE_DBG_HTTP, "Request created.\n");    return req;}static void set_body_size(ne_request *req, size_t size){    req->body_size = size;    ne_print_request_header(req, "Content-Length", "%" NE_FMT_SIZE_T, size);}void ne_set_request_body_buffer(ne_request *req, const char *buffer,				size_t size){    req->body.buf.buffer = buffer;    req->body_cb = body_string_send;    req->body_ud = req;    set_body_size(req, size);}void ne_set_request_body_provider(ne_request *req, size_t bodysize,				  ne_provide_body provider, void *ud){    req->body_cb = provider;    req->body_ud = ud;    set_body_size(req, bodysize);}int ne_set_request_body_fd(ne_request *req, int fd){    struct stat bodyst;    /* Get file length */    if (fstat(fd, &bodyst) < 0) {	char err[200];	ne_strerror(errno, err, sizeof err);	ne_set_error(req->session, _("Could not determine file length: %s"),		     err);	NE_DEBUG(NE_DBG_HTTP, "Stat failed: %s\n", err);	return -1;    }    req->body.fd = fd;    req->body_cb = body_fd_send;    req->body_ud = req;    set_body_size(req, bodyst.st_size);    return 0;}void ne_add_request_header(ne_request *req, const char *name, 			   const char *value){    ne_buffer_concat(req->headers, name, ": ", value, EOL, NULL);}void ne_print_request_header(ne_request *req, const char *name,			     const char *format, ...){    va_list params;    char buf[BUFSIZ];        va_start(params, format);    ne_vsnprintf(buf, sizeof buf, format, params);    va_end(params);        ne_buffer_concat(req->headers, name, ": ", buf, EOL, NULL);}voidne_add_response_header_handler(ne_request *req, const char *name, 			       ne_header_handler hdl, void *userdata){    struct header_handler *new = ne_calloc(sizeof *new);    unsigned int hash;    new->name = ne_strdup(name);    new->handler = hdl;    new->userdata = userdata;    hash = hash_and_lower(new->name);    new->next = req->header_handlers[hash];    req->header_handlers[hash] = new;}void ne_add_response_header_catcher(ne_request *req, 				    ne_header_handler hdl, void *userdata){    struct header_handler *new = ne_calloc(sizeof *new);    new->handler = hdl;    new->userdata = userdata;    new->next = req->header_catchers;    req->header_catchers = new;}void ne_add_response_body_reader(ne_request *req, ne_accept_response acpt,				 ne_block_reader rdr, void *userdata){    struct body_reader *new = ne_malloc(sizeof *new);    new->accept_response = acpt;    new->handler = rdr;    new->userdata = userdata;    new->next = req->body_readers;    req->body_readers = new;}void ne_request_destroy(ne_request *req) {    struct body_reader *rdr, *next_rdr;    struct header_handler *hdlr, *next_hdlr;    struct hook *hk, *next_hk;    int n;    ne_free(req->uri);    ne_free(req->method);    for (rdr = req->body_readers; rdr != NULL; rdr = next_rdr) {	next_rdr = rdr->next;	ne_free(rdr);    }    for (hdlr = req->header_catchers; hdlr != NULL; hdlr = next_hdlr) {	next_hdlr = hdlr->next;	ne_free(hdlr);    }    for (n = 0; n < HH_HASHSIZE; n++) {	for (hdlr = req->header_handlers[n]; hdlr != NULL; 	     hdlr = next_hdlr) {	    next_hdlr = hdlr->next;	    ne_free(hdlr->name);	    ne_free(hdlr);	}    }    ne_buffer_destroy(req->headers);    NE_DEBUG(NE_DBG_HTTP, "Running destroy hooks.\n");    for (hk = req->session->destroy_req_hooks; hk; hk = hk->next) {	ne_destroy_req_fn fn = (ne_destroy_req_fn)hk->fn;	fn(req, hk->userdata);    }    for (hk = req->private; hk; hk = next_hk) {	next_hk = hk->next;	ne_free(hk);    }    if (req->status.reason_phrase)	ne_free(req->status.reason_phrase);    NE_DEBUG(NE_DBG_HTTP, "Request ends.\n");    ne_free(req);}/* Reads a block of the response into buffer, which is of size buflen. * Returns number of bytes read, 0 on end-of-response, or NE_* on error. * TODO?: only make one actual read() call in here...  */static int read_response_block(ne_request *req, struct ne_response *resp, 			       char *buffer, size_t *buflen) {    size_t willread;    ssize_t readlen;    ne_socket *sock = req->session->socket;    switch (resp->mode) {    case R_CHUNKED:	/* We are doing a chunked transfer-encoding.	 * It goes:  `SIZE CRLF CHUNK CRLF SIZE CRLF CHUNK CRLF ...'	 * ended by a `CHUNK CRLF 0 CRLF', a 0-sized chunk.	 * The slight complication is that we have to cope with	 * partial reads of chunks.	 * For this reason, resp.chunk_left contains the number of	 * bytes left to read in the current chunk.	 */	if (resp->chunk_left == 0) {	    unsigned long int chunk_len;	    char *ptr;	    /* We are at the start of a new chunk. */	    NE_DEBUG(NE_DBG_HTTP, "New chunk.\n");	    SOCK_ERR(req, ne_sock_readline(sock, buffer, *buflen),		     _("Could not read chunk size"));	    NE_DEBUG(NE_DBG_HTTP, "[Chunk Size] < %s", buffer);	    chunk_len = strtoul(buffer, &ptr, 16);	    /* limit chunk size to <= UINT_MAX, so it will probably	     * fit in a size_t. */	    if (ptr == buffer || 		chunk_len == ULONG_MAX || chunk_len > UINT_MAX) {		return aborted(req, _("Could not parse chunk size"), 0);	    }	    NE_DEBUG(NE_DBG_HTTP, "Got chunk size: %lu\n", chunk_len);	    if (chunk_len == 0) {		/* Zero-size chunk == end of response. */		NE_DEBUG(NE_DBG_HTTP, "Zero-size chunk.\n");		*buflen = 0;		return NE_OK;	    }	    resp->chunk_left = chunk_len;	}	willread = resp->chunk_left;	break;    case R_CLENGTH:	willread = resp->left;	break;    case R_TILLEOF:	willread = *buflen;	break;    case R_NO_BODY:    default:	willread = 0;	break;    }    if (willread > *buflen) willread = *buflen;    else if (willread == 0) {	*buflen = 0;	return 0;    }    NE_DEBUG(NE_DBG_HTTP,	     "Reading %" NE_FMT_SIZE_T " bytes of response body.\n", willread);    readlen = ne_sock_read(sock, buffer, willread);    /* EOF is only valid when response body is delimited by it.     * Strictly, an SSL truncation should not be treated as an EOF in     * any case, but SSL servers are just too buggy.  */    if (resp->mode == R_TILLEOF && 	(readlen == NE_SOCK_CLOSED || readlen == NE_SOCK_TRUNC)) {	NE_DEBUG(NE_DBG_HTTP, "Got EOF.\n");	req->can_persist = 0;	readlen = 0;    } else if (readlen < 0) {	return aborted(req, _("Could not read response body"), readlen);    } else {	NE_DEBUG(NE_DBG_HTTP, "Got %" NE_FMT_SSIZE_T " bytes.\n", readlen);    }    /* safe to cast: readlen guaranteed to be >= 0 above */    *buflen = (size_t)readlen;    NE_DEBUG(NE_DBG_HTTPBODY,	     "Read block (%" NE_FMT_SSIZE_T " bytes):\n[%.*s]\n",	     readlen, (int)readlen, buffer);    if (resp->mode == R_CHUNKED) {	resp->chunk_left -= readlen;	if (resp->chunk_left == 0) {	    char crlfbuf[2];	    /* If we've read a whole chunk, read a CRLF */	    readlen = ne_sock_fullread(sock, crlfbuf, 2);            if (readlen < 0)                return aborted(req, _("Could not read chunk delimiter"),                               readlen);            else if (crlfbuf[0] != '\r' || crlfbuf[1] != '\n')                return aborted(req, _("Chunk delimiter was invalid"), 0);	}    } else if (resp->mode == R_CLENGTH) {	resp->left -= readlen;    }    return NE_OK;}ssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen){    struct body_reader *rdr;    size_t readlen = buflen;    if (read_response_block(req, &req->resp, buffer, &readlen))	return -1;    req->resp.total += readlen;    if (req->session->progress_cb) {	req->session->progress_cb(req->session->progress_ud, req->resp.total, 				  (req->resp.mode==R_CLENGTH)?req->resp.length:-1);    }    /* TODO: call the readers when this fails too. */    for (rdr = req->body_readers; rdr!=NULL; rdr=rdr->next) {	if (rdr->use) rdr->handler(rdr->userdata, buffer, readlen);    }        return readlen;}/* Build the request string, returning the buffer. */static ne_buffer *build_request(ne_request *req) {    struct hook *hk;    ne_buffer *buf = ne_buffer_create();    /* Add Request-Line and Host header: */    ne_buffer_concat(buf, req->method, " ", req->uri, " HTTP/1.1" EOL,		     "Host: ", req->session->server.hostport, EOL, NULL);        /* Add custom headers: */    ne_buffer_append(buf, req->headers->data, ne_buffer_size(req->headers));#define E100 "Expect: 100-continue" EOL    if (req->use_expect100)	ne_buffer_append(buf, E100, strlen(E100));    NE_DEBUG(NE_DBG_HTTP, "Running pre_send hooks\n");    for (hk = req->session->pre_send_hooks; hk!=NULL; hk = hk->next) {	ne_pre_send_fn fn = (ne_pre_send_fn)hk->fn;	fn(req, hk->userdata, buf);    }        ne_buffer_append(buf, "\r\n", 2);    return buf;}#ifdef NE_DEBUGGING#define DEBUG_DUMP_REQUEST(x) dump_request(x)static void dump_request(const char *request){     if ((NE_DBG_HTTPPLAIN&ne_debug_mask) == NE_DBG_HTTPPLAIN) { 	/* Display everything mode */	NE_DEBUG(NE_DBG_HTTP, "Sending request headers:\n%s", request);    } else {	/* Blank out the Authorization paramaters */	char *reqdebug = ne_strdup(request), *pnt = reqdebug;	while ((pnt = strstr(pnt, "Authorization: ")) != NULL) {	    for (pnt += 15; *pnt != '\r' && *pnt != '\0'; pnt++) {		*pnt = 'x';	    }	}	NE_DEBUG(NE_DBG_HTTP, "Sending request headers:\n%s", reqdebug);	ne_free(reqdebug);    }}#else#define DEBUG_DUMP_REQUEST(x)#endif /* DEBUGGING *//* remove trailing EOL from 'buf', where strlen(buf) == *len.  *len is * adjusted in accordance with any changes made to the string to * remain equal to strlen(buf). */static inline void strip_eol(char *buf, ssize_t *len){    char *pnt = &buf[*len-1];    while (pnt >= buf && (*pnt == '\r' || *pnt == '\n')) {	*pnt-- = '\0';	(*len)--;    }}/* For accurate persistent connection handling, for any write() or * read() operation for a new request on an already-open connection, * an EOF or RST error MUST be treated as a persistent connection * timeout, and the request retried on a new connection.  Once a * read() operation has succeeded, any subsequent error MUST be * treated as fatal.  A 'retry' flag is used; retry=1 represents the * first case, retry=0 the latter. *//* RETRY_RET() crafts a function return value given the 'retry' flag, * the socket error 'code', and the return value 'acode' from the * aborted() function. */#define RETRY_RET(retry, code, acode) \((((code) == NE_SOCK_CLOSED || (code) == NE_SOCK_RESET || \ (code) == NE_SOCK_TRUNC) && retry) ? NE_RETRY : (acode))/* Read and parse response status-line into 'status'.  'retry' is non-zero * if an NE_RETRY should be returned if an EOF is received. */static int read_status_line(ne_request *req, ne_status *status, int retry){    char *buffer = req->respbuf;    ssize_t ret;    ret = ne_sock_readline(req->session->socket, buffer, sizeof req->respbuf);    if (ret <= 0) {	int aret = aborted(req, _("Could not read status line"), ret);	return RETRY_RET(retry, ret, aret);    }        NE_DEBUG(NE_DBG_HTTP, "[status-line] < %s", buffer);    strip_eol(buffer, &ret);        if (status->reason_phrase) ne_free(status->reason_phrase);    memset(status, 0, sizeof *status);    if (ne_parse_statusline(buffer, status))	return aborted(req, _("Could not parse response status line."), 0);    return 0;}/* Discard a set of message headers. */static int discard_headers(ne_request *req){    do {

⌨️ 快捷键说明

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