📄 http.c
字号:
if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0) { DEBUG_puts("httpGetLength: chunked request!"); http->data_encoding = HTTP_ENCODE_CHUNKED; http->data_remaining = 0; } else { http->data_encoding = HTTP_ENCODE_LENGTH; /* * The following is a hack for HTTP servers that don't send a * content-length or transfer-encoding field... * * If there is no content-length then the connection must close * after the transfer is complete... */ if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0') http->data_remaining = 2147483647; else http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]); DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining)); } return (http->data_remaining);}/* * 'http_field()' - Return the field index for a field name. */static http_field_t /* O - Field index */http_field(const char *name) /* I - String name */{ int i; /* Looping var */ for (i = 0; i < HTTP_FIELD_MAX; i ++) if (strcasecmp(name, http_fields[i]) == 0) return ((http_field_t)i); return (HTTP_FIELD_UNKNOWN);}/* * 'http_send()' - Send a request with all fields and the trailing blank line. */static int /* O - 0 on success, non-zero on error */http_send(http_t *http, /* I - HTTP data */ http_state_t request, /* I - Request code */ const char *uri) /* I - URI */{ int i; /* Looping var */ char *ptr, /* Pointer in buffer */ buf[1024]; /* Encoded URI buffer */ static const char * const codes[] = { /* Request code strings */ NULL, "OPTIONS", "GET", NULL, "HEAD", "POST", NULL, NULL, "PUT", NULL, "DELETE", "TRACE", "CLOSE" }; static const char hex[] = "0123456789ABCDEF"; /* Hex digits */ DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n", http, codes[request], uri)); if (http == NULL || uri == NULL) return (-1); /* * Encode the URI as needed... */ for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++) if (*uri <= ' ' || *uri >= 127) { if (ptr < (buf + sizeof(buf) - 1)) *ptr ++ = '%'; if (ptr < (buf + sizeof(buf) - 1)) *ptr ++ = hex[(*uri >> 4) & 15]; if (ptr < (buf + sizeof(buf) - 1)) *ptr ++ = hex[*uri & 15]; } else *ptr ++ = *uri; *ptr = '\0'; /* * See if we had an error the last time around; if so, reconnect... */ if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST) httpReconnect(http); /* * Send the request header... */ http->state = request; if (request == HTTP_POST || request == HTTP_PUT) http->state ++; http->status = HTTP_CONTINUE;#ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) { httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0"); }#endif /* HAVE_SSL */ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) { http->status = HTTP_ERROR; return (-1); } for (i = 0; i < HTTP_FIELD_MAX; i ++) if (http->fields[i][0] != '\0') { DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i])); if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1) { http->status = HTTP_ERROR; return (-1); } } if (httpPrintf(http, "\r\n") < 1) { http->status = HTTP_ERROR; return (-1); } httpClearFields(http); return (0);}/* * 'http_wait()' - Wait for data available on a connection. */static int /* O - 1 if data is available, 0 otherwise */http_wait(http_t *http, /* I - HTTP data */ int msec) /* I - Milliseconds to wait */{#ifndef WIN32 struct rlimit limit; /* Runtime limit */#endif /* !WIN32 */ struct timeval timeout; /* Timeout */ int nfds; /* Result from select() */ int set_size; /* Size of select set */ DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec)); /* * Check the SSL/TLS buffers for data first... */#ifdef HAVE_SSL if (http->tls) {# ifdef HAVE_LIBSSL if (SSL_pending((SSL *)(http->tls))) return (1);# elif defined(HAVE_GNUTLS) if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session)) return (1);# elif defined(HAVE_CDSASSL) size_t bytes; /* Bytes that are available */ if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0) return;# endif /* HAVE_LIBSSL */ }#endif /* HAVE_SSL */ /* * Then try doing a select() to poll the socket... */ if (!http->input_set) {#ifdef WIN32 /* * Windows has a fixed-size select() structure, different (surprise, * surprise!) from all UNIX implementations. Just allocate this * fixed structure... */ http->input_set = calloc(1, sizeof(fd_set));#else /* * Allocate the select() input set based upon the max number of file * descriptors available for this process... */ getrlimit(RLIMIT_NOFILE, &limit); set_size = (limit.rlim_cur + 31) / 8 + 4; if (set_size < sizeof(fd_set)) set_size = sizeof(fd_set); http->input_set = calloc(1, set_size);#endif /* WIN32 */ if (!http->input_set) return (0); } do { FD_SET(http->fd, http->input_set); if (msec >= 0) { timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout); } else nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL); }#ifdef WIN32 while (nfds < 0 && WSAGetLastError() == WSAEINTR);#else while (nfds < 0 && errno == EINTR);#endif /* WIN32 */ FD_CLR(http->fd, http->input_set); return (nfds > 0);}#ifdef HAVE_SSL/* * 'http_upgrade()' - Force upgrade to TLS encryption. */static int /* O - Status of connection */http_upgrade(http_t *http) /* I - HTTP data */{ int ret; /* Return value */ http_t myhttp; /* Local copy of HTTP data */ DEBUG_printf(("http_upgrade(%p)\n", http)); /* * Copy the HTTP data to a local variable so we can do the OPTIONS * request without interfering with the existing request data... */ memcpy(&myhttp, http, sizeof(myhttp)); /* * Send an OPTIONS request to the server, requiring SSL or TLS * encryption on the link... */ httpClearFields(&myhttp); httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade"); httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0"); if ((ret = httpOptions(&myhttp, "*")) == 0) { /* * Wait for the secure connection... */ while (httpUpdate(&myhttp) == HTTP_CONTINUE); } httpFlush(&myhttp); /* * Copy the HTTP data back over, if any... */ http->fd = myhttp.fd; http->error = myhttp.error; http->activity = myhttp.activity; http->status = myhttp.status; http->version = myhttp.version; http->keep_alive = myhttp.keep_alive; http->used = myhttp.used; if (http->used) memcpy(http->buffer, myhttp.buffer, http->used); http->auth_type = myhttp.auth_type; http->nonce_count = myhttp.nonce_count; memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce)); http->tls = myhttp.tls; http->encryption = myhttp.encryption; /* * See if we actually went secure... */ if (!http->tls) { /* * Server does not support HTTP upgrade... */ DEBUG_puts("Server does not support HTTP upgrade!");# ifdef WIN32 closesocket(http->fd);# else close(http->fd);# endif http->fd = -1; return (-1); } else return (ret);}/* * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. */static int /* O - Status of connection */http_setup_ssl(http_t *http) /* I - HTTP data */{# ifdef HAVE_LIBSSL SSL_CTX *context; /* Context for encryption */ SSL *conn; /* Connection for encryption */# elif defined(HAVE_GNUTLS) http_tls_t *conn; /* TLS session object */ gnutls_certificate_client_credentials *credentials; /* TLS credentials */# elif defined(HAVE_CDSASSL) SSLContextRef conn; /* Context for encryption */ OSStatus error; /* Error info */# endif /* HAVE_LIBSSL */ DEBUG_printf(("http_setup_ssl(http=%p)\n", http));# ifdef HAVE_LIBSSL context = SSL_CTX_new(SSLv23_client_method()); conn = SSL_new(context); SSL_set_fd(conn, http->fd); if (SSL_connect(conn) != 1) {# ifdef DEBUG unsigned long error; /* Error code */ while ((error = ERR_get_error()) != 0) printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));# endif /* DEBUG */ SSL_CTX_free(context); SSL_free(conn);# ifdef WIN32 http->error = WSAGetLastError();# else http->error = errno;# endif /* WIN32 */ http->status = HTTP_ERROR; return (HTTP_ERROR); }# elif defined(HAVE_GNUTLS) conn = (http_tls_t *)malloc(sizeof(http_tls_t)); if (conn == NULL) { http->error = errno; http->status = HTTP_ERROR; return (-1); } credentials = (gnutls_certificate_client_credentials *) malloc(sizeof(gnutls_certificate_client_credentials)); if (credentials == NULL) { free(conn); http->error = errno; http->status = HTTP_ERROR; return (-1); } gnutls_certificate_allocate_credentials(credentials); gnutls_init(&(conn->session), GNUTLS_CLIENT); gnutls_set_default_priority(conn->session); gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials); gnutls_transport_set_ptr(conn->session, http->fd); if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS) { http->error = errno; http->status = HTTP_ERROR; return (-1); } conn->credentials = credentials;# elif defined(HAVE_CDSASSL) error = SSLNewContext(false, &conn); if (!error) error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc); if (!error) error = SSLSetConnection(conn, (SSLConnectionRef)http->fd); if (!error) error = SSLSetAllowsExpiredCerts(conn, true); if (!error) error = SSLSetAllowsAnyRoot(conn, true); if (!error) error = SSLHandshake(conn); if (error != 0) { http->error = error; http->status = HTTP_ERROR; SSLDisposeContext(conn); close(http->fd); return (-1); }# endif /* HAVE_CDSASSL */ http->tls = conn; return (0);}/* * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection. */static voidhttp_shutdown_ssl(http_t *http) /* I - HTTP data */{# ifdef HAVE_LIBSSL SSL_CTX *context; /* Context for encryption */ SSL *conn; /* Connection for encryption */ conn = (SSL *)(http->tls); context = SSL_get_SSL_CTX(conn); SSL_shutdown(conn); SSL_CTX_free(context); SSL_free(conn);# elif defined(HAVE_GNUTLS) http_tls_t *conn; /* Encryption session */ gnutls_certificate_client_credentials *credentials; /* TLS credentials */ conn = (http_tls_t *)(http->tls); credentials = (gnutls_certificate_client_credentials *)(conn->credentials); gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); gnutls_deinit(conn->session); gnutls_certificate_free_credentials(*credentials); free(credentials); free(conn);# elif defined(HAVE_CDSASSL) SSLClose((SSLContextRef)http->tls); SSLDisposeContext((SSLContextRef)http->tls);# endif /* HAVE_LIBSSL */ http->tls = NULL;}/* * 'http_read_ssl()' - Read from a SSL/TLS connection. */static int /* O - Bytes read */http_read_ssl(http_t *http, /* I - HTTP data */ char *buf, /* I - Buffer to store data */ int len) /* I - Length of buffer */{# if defined(HAVE_LIBSSL) return (SSL_read((SSL *)(http->tls), buf, len));# elif defined(HAVE_GNUTLS) return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));# elif defined(HAVE_CDSASSL) OSStatus error; /* Error info */ size_t processed; /* Number of bytes processed */ error = SSLRead((SSLContextRef)http->tls, buf, len, &processed); if (error == 0) return (processed); else { http->error = error; return (-1); }# endif /* HAVE_LIBSSL */}/* * 'http_write_ssl()' - Write to a SSL/TLS connection. */static int /* O - Bytes written */http_write_ssl(http_t *http, /* I - HTTP data */ const char *buf, /* I - Buffer holding data */ int len) /* I - Length of buffer */{# if defined(HAVE_LIBSSL) return (SSL_write((SSL *)(http->tls), buf, len));# elif defined(HAVE_GNUTLS) return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));# elif defined(HAVE_CDSASSL) OSStatus error; /* Error info */ size_t processed; /* Number of bytes processed */ error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed); if (error == 0) return (processed); else { http->error = error; return (-1); }# endif /* HAVE_LIBSSL */}# if defined(HAVE_CDSASSL)/* * 'CDSAReadFunc()' - Read function for CDSA decryption code. */static OSStatus /* O - -1 on error, 0 on success */CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */ void *data, /* I - Data buffer */ size_t *dataLength) /* IO - Number of bytes */{ ssize_t bytes; /* Number of bytes read */ bytes = recv((int)connection, data, *dataLength, 0); if (bytes >= 0) { *dataLength = bytes; return (0); } else return (-1);}/* * 'CDSAWriteFunc()' - Write function for CDSA encryption code. */static OSStatus /* O - -1 on error, 0 on success */CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */ const void *data, /* I - Data buffer */ size_t *dataLength) /* IO - Number of bytes */{ ssize_t bytes; bytes = write((int)connection, data, *dataLength); if (bytes >= 0) { *dataLength = bytes; return (0); } else return (-1);}# endif /* HAVE_CDSASSL */#endif /* HAVE_SSL *//* * End of "$Id: http.c,v 1.144 2005/01/03 19:29:45 mike Exp $". */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -