📄 http.c
字号:
request->url->offset_end = request->size - 1; len = request->url->offset_end - request->url->offset + 1; } /*fprintf(stderr,"Read %lu -> %lu (%ld)\n", (RMuint32) request->url->offset, (RMuint32) request->url->offset_end, (RMuint32) request->url->offset_end - (RMuint32) request->url->offset + 1);*/ /* Keep them for later */ start_save = request->url->offset; end_save = request->url->offset_end; plen = end_save - start_save + 1; start = ( start_save & (~((1<<CACHELOG2)-1))); offset = start_save & ((1<<CACHELOG2)-1); do { RMint64 read = mmin(plen, CACHEBUFFERSIZE - offset); cached = get_buffer_cache(request->cache, start, &buf_cache); RMDBGLOG((HTTPDEBUG,"request = %p, cache = %p, buf_cache = %p\n", request, request->cache, buf_cache)); if (cached < 0){ /* Not cached */ request->url->offset = start; request->url->offset_end = mmin(start+CACHEBUFFERSIZE-1, (request->size-1)); status = __http_read(v, buf_cache); if (status < 0){ RMDBGLOG((ENABLE,"Error reading %lu->%lu : %ld %ld %ld\n", (RMuint32) request->url->offset, (RMuint32) request->url->offset_end, status, request->conn->err, fetchLastErrCode)); request->url->offset = start_save; request->url->offset_end = end_save; return status; } } bcopy(buf_cache+offset, buf, read); buf+=read; plen-=read; offset = 0; start += CACHEBUFFERSIZE; } while (plen > 0); request->url->offset = end_save + 1; return(end_save-start_save+1);}static RMint32__http_read_uncached(void *v, RMuint8 *buf, RMuint32 len){ struct httpio *io = (struct httpio *)v; struct http_request_s *request = io->request; RMint32 total_read = 0; RMint32 nread = 0; while (1){ if (request->need_reopen){ RMint32 status; RMDBGLOG((HTTPDEBUG,"Need to open a new connection\n")); status = _fetch_close(request->conn); if (status < 0) perror("Error closing previous connection, keep going"); /* New connection */ status = _http_single_request(request); /* No redirect at this point allowed */ if (status <= 0){ if (request->last_read_short){ /* EOF */ io->eof = 1; request->last_read_short = 0; return total_read; } else { /* Error */ return(-1); } } request->need_reopen = 0; /* Reset the chunk size */ io->chunksize = 0; } while (len > 0){ nread = _http_fillbuf(io, len, buf); if (nread <= 0){ RMDBGLOG((HTTPDEBUG,"nread <= 0 : %ld\n", total_read)); /* For some servers (Intel DTCPIP for example), * a bad range is not a problem, so the request * above will not fail at EOF, but the read * should at least ... */ if (request->last_read_short) return total_read; break; } total_read += nread; len -= nread; buf += nread; } if (!total_read && io->error){ RMDBGLOG((ENABLE,"IO error %ld\n", io->error)); return (-1); } request->url->offset += total_read; if (nread == 0){ /* Might be end of file or peer closed connection (time * out, ...), so try to reopen, if it was end of file, * it will fail */ request->need_reopen = 1; request->last_read_short = 1; continue; } request->last_read_short = 0; return (total_read); } return(-1);} /* * Read function */static RMint32_http_readfn(void *v, RMuint8 *buf, RMuint32 len){ struct httpio *io = (struct httpio *)v; struct http_request_s *request = io->request; if (io->error){ RMDBGLOG((ENABLE,"IO error %ld\n", io->error)); return (-1); } if (io->eof){ RMDBGLOG((ENABLE,"IO EOF %ld\n", io->eof)); return (0); } if (request->open) return (__http_read_cached(v, buf, len)); /* If custom decryption hooks are being used, ... */ if ((request->custom_cookie != NULL) && (request->custom_hooks != NULL) && (request->custom_hooks->preread != NULL) && (request->custom_hooks->postread != NULL)) { RMint32 result; RMint32 new_read_size; RMint32 nread; RMint32 actual_read; RMint32 more_data = 0; RMint32 bytes_left = len; RMint32 total_read = 0; RMuint8 *buf_ptr = buf; do { /* If reopening the connection and resynchronizing the decryption block boundary are necessary, ... */ if ((request->need_reopen) && (request->custom_hooks->reopen != NULL)) { if ((result = request->custom_hooks->reopen(request->custom_cookie)) < 0) return result; } /* Truncate read size if necessary to prevent reading beyond a decryption block boundary */ if ((new_read_size = request->custom_hooks->preread(request->custom_cookie, buf_ptr, bytes_left)) <= 0) return new_read_size; /* Fill up the buffer without going beyond the end of a decryption block boundary */ if ((nread = __http_read_uncached(v, buf_ptr, new_read_size)) <= 0) return nread; /* Decrypt the data */ if ((actual_read = request->custom_hooks->postread(request->custom_cookie, buf_ptr, nread, &more_data)) <= 0) return actual_read; /* Update the position */ bytes_left -= actual_read; total_read += actual_read; buf_ptr += actual_read; } while ((more_data != 0) && (bytes_left > 0)); return(total_read); } return (__http_read_uncached(v, buf, len));}RMint32 fetchRead(RMuint8 *buf, RMint32 size, HTTPFile * file){ return(_http_readfn((void *)file, buf, (RMuint32) size));}/* * Close function */static RMint32_http_closefn(void *v){ struct httpio *io = (struct httpio *)v; RMint32 r; struct http_request_s *request = io->request; /* Perform a custom close hook if present */ if ((request->custom_cookie != NULL) && (request->custom_hooks != NULL) && (request->custom_hooks->close != NULL)) request->custom_hooks->close(request->custom_cookie); r = _fetch_close(CONN(io)); if (io->request->purl) fetchFreeURL(io->request->purl); if (io->request->url) fetchFreeURL(io->request->url); if (io->request->host) RMFree(io->request->host); if (io->request->cache) destroy_cache(io->request->cache); if (io->request->custom_header != NULL) RMFree(io->request->custom_header); if (io->request) RMFree(io->request); RMFree(io); return (r);}RMint32 fetchClose(HTTPFile * file){ return (_http_closefn((void *) file));}/* * Seek function */static RMint32 _http_seekn(void *cookie, RMint64 *position, RMint32 whence){ struct httpio *io = (struct httpio *)cookie; struct http_request_s *request = io->request; RMint64 newpos = -1; /* Perform a custom seek hook if present */ if ((request->custom_cookie != NULL) && (request->custom_hooks != NULL) && (request->custom_hooks->seek != NULL)) request->custom_hooks->seek(request->custom_cookie, *position, whence); if (whence == SEEK_SET){ newpos = *position; }else if (whence == SEEK_CUR){ newpos = request->url->offset + *position; }else if (whence == SEEK_END){ newpos = (RMint64) request->size + *position; } RMDBGLOG((HTTPDEBUG,"Seeking : newpos = %lld pos = %lld\n", newpos, *position)); if (newpos < 0){ RMDBGLOG((ENABLE,"Seeking out of bounds : %lld\n", newpos)); return(-1); } /* See man lseek, seeking beyond end of file should not return an error * (allow creation of sparse file for example) */#if 0 if ( (request->size != -1) && (newpos > request->size) ){ RMDBGLOG((ENABLE,"Seeking out of bounds : size = %lld, newpos = %lld\n", request->size, newpos)); return(-1); }#endif if ((request->url->offset != newpos) && (request->open == 0)){ /* Closed connection request, we need to reopen a connection */ if (request->open == 0) request->need_reopen = 1; } request->url->offset = newpos; *position = newpos; io->eof = 0; return(0);}RMint32 fetchSeek(HTTPFile * file, RMint64 offset, RMint32 whence){ RMint64 pos=offset; return(_http_seekn((void *) file, &pos, whence));}RMint64 fetchTell(HTTPFile * file){ RMint64 pos=0; RMint32 status; SAFE(_http_seekn((void *) file, &pos, SEEK_CUR)); return pos;} /* * Wrap it up */static HTTPFile *_http_funopen(struct http_request_s *request){ struct httpio *io; if (request == NULL) return(NULL); if ((io = RMCalloc(1, sizeof(*io))) == NULL) { _fetch_syserr(); return (NULL); } io->request = request; return (HTTPFile *)io;}/***************************************************************************** * Helper functions for talking to the server and parsing its replies *//* Header types */typedef enum { hdr_syserror = -2, hdr_error = -1, hdr_end = 0, hdr_unknown = 1, hdr_content_length, hdr_content_range, hdr_last_modified, hdr_location, hdr_transfer_encoding, hdr_www_authenticate, hdr_connection} hdr_t;/* Names of interesting headers */static struct { hdr_t num; const RMascii *name;} hdr_names[] = { { hdr_content_length, "Content-Length" }, { hdr_content_range, "Content-Range" }, { hdr_last_modified, "Last-Modified" }, { hdr_location, "Location" }, { hdr_transfer_encoding, "Transfer-Encoding" }, { hdr_www_authenticate, "WWW-Authenticate" }, { hdr_connection, "Connection"}, { hdr_unknown, NULL },};/* * Send a formatted line; optionally echo to terminal */static RMint32_http_cmd(conn_t *conn, const RMascii *fmt, ...){#define MAXLINE 1024 va_list ap; RMuint32 len; RMascii msg[MAXLINE]; RMascii *long_msg = NULL; RMint32 r; RMuint32 long_size = MAXLINE; va_start(ap, fmt); len = vsnprintf(msg, MAXLINE, fmt, ap); va_end(ap); if (len >= MAXLINE){ do { if (long_msg) RMFree(long_msg); long_size = long_size * 2; long_msg = RMMalloc(long_size); if (long_msg == NULL){ errno = ENOMEM; goto error; } va_start(ap, fmt); len = vsnprintf(long_msg, long_size, fmt, ap); va_end(ap); } while (len >= long_size); } if (long_msg) r = _fetch_putln(conn, long_msg, len); else r = _fetch_putln(conn, msg, len); if (r < 0) goto error; return (0);error: _fetch_syserr(); if (long_msg) RMFree(long_msg); return(-1); }/* * Get and parse status line */static RMint32_http_get_reply(conn_t *conn){ RMascii *p; if (_fetch_getln(conn) == -1){ return (-1); } /* * A valid status line looks like "HTTP/m.n xyz reason" where m * and n are the major and minor protocol version numbers and xyz * is the reply code. * Unfortunately, there are servers out there (NCSA 1.5.1, to name * just one) that do not send a version number, so we can't rely * on finding one, but if we do, insist on it being 1.0 or 1.1. * We don't care about the reason phrase. */ if (conn->buflen >= 4) { if (strncmp((RMascii *)conn->buf, "HTTP", 4) != 0) return (HTTP_PROTOCOL_ERROR); } else { /* * Check if a chunked-body ending was received from the server for previous transactions. * Some servers which encode using chunked streams, * finish their transactions with a chunk body terminator like "0\r\n\r\n". */ if (strncmp((RMascii *)conn->buf, "0\r\n", 3) != 0){ return (HTTP_PROTOCOL_ERROR); } if (_fetch_getln(conn) == -1){ return (-1); } if (strncmp((RMascii *)conn->buf, "\r\n", 2) != 0){ return (HTTP_PROTOCOL_ERROR); } /* * If found "0\r\n\r\n" left inside connection buffers, discard it and start to read the HTTP header. */ if (_fetch_getln(conn) == -1){ return (-1); } if (strncmp((RMascii *)conn->buf, "HTTP", 4) != 0) return (HTTP_PROTOCOL_ERROR); } p = (RMascii *)conn->buf + 4; if (*p == '/') { if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1')) return (HTTP_PROTOCOL_ERROR); p += 4; } if (*p != ' ' || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3])) return (HTTP_PROTOCOL_ERROR); conn->err = (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0'); return (conn->err);}/* * Check a header; if the type matches the given string, return a pointer * to the beginning of the value. */static const RMascii *_http_match(const RMascii *str, const RMascii *hdr){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -