📄 http_fopen_wrapper.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Rasmus Lerdorf <rasmus@php.net> | | Jim Winstead <jimw@php.net> | | Hartmut Holzgraefe <hholzgra@php.net> | | Wez Furlong <wez@thebrainroom.com> | +----------------------------------------------------------------------+ *//* $Id: http_fopen_wrapper.c,v 1.53.2.20.2.10 2007/01/01 09:46:48 sebastian Exp $ */ #include "php.h"#include "php_globals.h"#include "php_streams.h"#include "php_network.h"#include "php_ini.h"#include "ext/standard/basic_functions.h"#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef PHP_WIN32#include <windows.h>#include <winsock.h>#define O_RDONLY _O_RDONLY#include "win32/param.h"#else#include <sys/param.h>#endif#include "php_standard.h"#include <sys/types.h>#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef PHP_WIN32#include <winsock.h>#elif defined(NETWARE) && defined(USE_WINSOCK)#include <novsock2.h>#else#include <netinet/in.h>#include <netdb.h>#if HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#endif#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)#undef AF_UNIX#endif#if defined(AF_UNIX)#include <sys/un.h>#endif#include "php_fopen_wrappers.h"#define HTTP_HEADER_BLOCK_SIZE 1024#define PHP_URL_REDIRECT_MAX 20#define HTTP_HEADER_USER_AGENT 1#define HTTP_HEADER_HOST 2#define HTTP_HEADER_AUTH 4#define HTTP_HEADER_FROM 8php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int header_init STREAMS_DC TSRMLS_DC){ php_stream *stream = NULL; php_url *resource = NULL; int use_ssl; char *scratch = NULL; char *tmp = NULL; char *ua_str = NULL; zval **ua_zval = NULL, **tmpzval = NULL; int scratch_len = 0; int body = 0; char location[HTTP_HEADER_BLOCK_SIZE]; zval **response_header = NULL; int reqok = 0; char *http_header_line = NULL; char tmp_line[128]; size_t chunk_size = 0, file_size = 0; int eol_detect, have_header = 0; tmp_line[0] = '\0'; if (redirect_max < 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Circular redirect, aborting."); return NULL; } if (strpbrk(mode, "aw+")) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections."); return NULL; } resource = php_url_parse(path); if (resource == NULL) { return NULL; } if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) { php_url_free(resource); return php_stream_open_wrapper_ex(path, mode, ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); } use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's'; /* choose default ports */ if (use_ssl && resource->port == 0) resource->port = 443; else if (resource->port == 0) resource->port = 80; stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, NULL, 0); if (stream == NULL) { eol_detect = 0; goto out; } /* avoid problems with auto-detecting when reading the headers -> the headers * are always in canonical \r\n format */ eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC); stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC); php_stream_context_set(stream, context); php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0); #ifdef HAVE_OPENSSL_EXT if (use_ssl) { if (context) { /* set the CN we expect to be on the remote cert. * You still need to have enabled verification (verify_peer) in the context for * this to have an effect */ zval *cn; ALLOC_INIT_ZVAL(cn); ZVAL_STRING(cn, resource->host, 1); php_stream_context_set_option(context, "ssl", "CN_match", cn); } if (php_stream_sock_ssl_activate(stream, 1) == FAILURE) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode"); php_stream_close(stream); stream = NULL; goto out; } }#endif if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) { if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) { scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval); scratch = emalloc(scratch_len); strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1); strcat(scratch, " "); } } if (!scratch) { scratch_len = strlen(path) + 32; scratch = emalloc(scratch_len); strcpy(scratch, "GET "); } /* file */ if (resource->path && *resource->path) strlcat(scratch, resource->path, scratch_len); else strlcat(scratch, "/", scratch_len); /* query string */ if (resource->query) { strlcat(scratch, "?", scratch_len); strlcat(scratch, resource->query, scratch_len); } /* protocol version we are speaking */ strlcat(scratch, " HTTP/1.0\r\n", scratch_len); /* send it */ php_stream_write(stream, scratch, strlen(scratch)); if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS && Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) { /* Remove newlines and spaces from start and end, php_trim will estrndup() */ tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC); if (strlen(tmp) > 0) { /* Output trimmed headers with \r\n at the end */ php_stream_write(stream, tmp, strlen(tmp)); php_stream_write(stream, "\r\n", sizeof("\r\n") - 1); /* Make lowercase for easy comparison against 'standard' headers */ php_strtolower(tmp, strlen(tmp)); if (strstr(tmp, "user-agent:")) { have_header |= HTTP_HEADER_USER_AGENT; } if (strstr(tmp, "host:")) { have_header |= HTTP_HEADER_HOST; } if (strstr(tmp, "from:")) { have_header |= HTTP_HEADER_FROM; } if (strstr(tmp, "authorization:")) { have_header |= HTTP_HEADER_AUTH; } } efree(tmp); } /* auth header if it was specified */ if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user && resource->pass) { /* decode the strings first */ php_url_decode(resource->user, strlen(resource->user)); php_url_decode(resource->pass, strlen(resource->pass)); /* scratch is large enough, since it was made large enough for the whole URL */ strcpy(scratch, resource->user); strcat(scratch, ":"); strcat(scratch, resource->pass); tmp = php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL); if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) { php_stream_write(stream, scratch, strlen(scratch)); php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0); } efree(tmp); tmp = NULL; } /* if the user has configured who they are, send a From: line */ if (((have_header & HTTP_HEADER_FROM) == 0) && cfg_get_string("from", &tmp) == SUCCESS) { if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0) { php_stream_write(stream, scratch, strlen(scratch)); } } /* Send Host: header so name-based virtual hosts work */ if ((have_header & HTTP_HEADER_HOST) == 0) { if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) { php_stream_write(stream, scratch, strlen(scratch)); } } else { if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) { php_stream_write(stream, scratch, strlen(scratch)); } } } if (context && php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS && Z_TYPE_PP(ua_zval) == IS_STRING) { ua_str = Z_STRVAL_PP(ua_zval); } else if (FG(user_agent)) { ua_str = FG(user_agent); } if (ua_str) {#define _UA_HEADER "User-Agent: %s\r\n" char *ua; size_t ua_len; ua_len = sizeof(_UA_HEADER) + strlen(ua_str); /* ensure the header is only sent if user_agent is not blank */ if (ua_len > sizeof(_UA_HEADER)) { ua = emalloc(ua_len + 1); if ((ua_len = snprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) { ua[ua_len] = 0; php_stream_write(stream, ua, ua_len); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header"); } if (ua) { efree(ua); } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -