Browse Source

- Remove legacy non-streams code (as discussed with Brad).

- Make get_http_header_value() work using case-insensitive compares
  for the header names, as per relevant RFC's.
- General performance boost for get_http_headers().
- Fix a crash bug when a malformed URL is passed to the soap client.
- Implement https:// support in the the soap client. (does not verify
  the remote server certificate; it provides an encrypted link only).
- Provide a hook for libxml to parse files using any registered PHP
  wrapper, including https://, ftps:// and any user-space streams.
migration/unlabaled-1.3.2
Wez Furlong 23 years ago
parent
commit
b68739f7f9
  1. 265
      ext/soap/php_http.c
  2. 18
      ext/soap/php_http.h
  3. 22
      ext/soap/php_soap.h
  4. 28
      ext/soap/php_xml.c
  5. 5
      ext/soap/php_xml.h
  6. 36
      ext/soap/soap.c

265
ext/soap/php_http.c

@ -7,7 +7,7 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
int buf_size,err,ret;
sdlPtr sdl;
php_url *phpurl = NULL;
SOAP_STREAM stream;
php_stream *stream;
zval **trace;
FETCH_THIS_SOCKET(stream);
@ -26,6 +26,7 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
if(!stream)
{
char *url;
int use_ssl;
if(!sdl)
{
@ -42,35 +43,46 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
}
phpurl = php_url_parse(url);
if (phpurl == NULL) {
php_error(E_ERROR, "Unable to parse URL \"%s\"", url);
}
use_ssl = strcmp(phpurl->scheme, "https") == 0;
#if !HAVE_OPENSSL_EXT
if (use_ssl) {
php_error(E_ERROR, "SSL support not available in this build");
}
#endif
if (phpurl->port == 0) {
if (strcmp(phpurl->scheme, "http") == 0)
phpurl->port = 80;
else if (strcmp(phpurl->scheme, "https") == 0)
phpurl->port = 443;
phpurl->port = use_ssl ? 443 : 80;
}
#ifdef PHP_HAVE_STREAMS
stream = php_stream_sock_open_host(phpurl->host, (unsigned short)phpurl->port, SOCK_STREAM, NULL, NULL);
#else
stream = get_socket(phpurl->host, phpurl->port, 10);
#endif
if(stream)
{
ret = zend_list_insert((void *)stream, le_http_socket);
add_property_resource(this_ptr, "httpsocket", ret);
zend_list_addref(ret);
#if HAVE_OPENSSL_EXT
/* fire up SSL, if requested */
if (use_ssl) {
if (FAILURE == php_stream_sock_ssl_activate(stream, 1)) {
php_error(E_ERROR, "SSL Connection attempt failed");
}
}
#endif
add_property_resource(this_ptr, "httpsocket", php_stream_get_resource_id(stream));
ret = zend_list_insert(phpurl, le_url);
add_property_resource(this_ptr, "httpurl", ret);
zend_list_addref(ret);
} else {
php_error(E_ERROR,"Could not connect to host");
php_error(E_ERROR, "Could not connect to host");
}
}
if(stream)
{
if (stream) {
zval **cookies;
char *header = "POST %s HTTP/1.1\r\nConnection: close\r\nAccept: text/html; text/xml; text/plain\r\nUser-Agent: PHP SOAP 0.1\r\nHost: %s\r\nContent-Type: text/xml\r\nContent-Length: %d\r\nSOAPAction: \"%s\"\r\n";
int size = strlen(header) + strlen(phpurl->host) + strlen(phpurl->path) + 10;
@ -88,11 +100,8 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
sprintf(soap_headers, header, phpurl->path, phpurl->host, buf_size, soapaction);
}
#ifdef PHP_HAVE_STREAMS
err = php_stream_write(stream, soap_headers, strlen(soap_headers));
#else
err = send(stream, soap_headers, strlen(soap_headers), 0);
#endif
if(err != (int)strlen(soap_headers))
php_error(E_ERROR,"Failed Sending HTTP Headers");
@ -120,31 +129,22 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
smart_str_appendl(&cookie_str, "\r\n", 2);
smart_str_0(&cookie_str);
#ifdef PHP_HAVE_STREAMS
err = php_stream_write(stream, cookie_str.c, cookie_str.len);
#else
err = send(stream, cookie_str.c, cookie_str.len,0);
#endif
if(err != (int)cookie_str.len)
php_error(E_ERROR,"Failed Sending HTTP Headers");
smart_str_free(&cookie_str);
}
#ifdef PHP_HAVE_STREAMS
err = php_stream_write(stream, "\r\n", 2);
#else
err = send(stream, "\r\n", 2, 0);
#endif
if(err != 2)
php_error(E_ERROR,"Failed Sending HTTP Headers");
#ifdef PHP_HAVE_STREAMS
err = php_stream_write(stream, buf, buf_size);
#else
err = send(stream, buf, buf_size, 0);
#endif
if(err != (int)strlen(buf))
php_error(E_ERROR,"Failed Sending HTTP Content");
@ -159,7 +159,7 @@ void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRML
int http_header_size, http_body_size, http_close;
sdlPtr sdl;
zval **socket_ref;
SOAP_STREAM stream;
php_stream *stream;
zval **trace;
FETCH_THIS_SDL(sdl);
@ -244,15 +244,9 @@ void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRML
}
*/
if(http_close)
{
#ifdef PHP_HAVE_STREAMS
if (http_close) {
php_stream_close(stream);
#else
SOCK_CLOSE(stream);
#endif
zend_list_delete(Z_RESVAL_PP(socket_ref));
zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", strlen("httpsocket") + 1);
zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
}
/* Check and see if the server even sent a xml document */
@ -336,164 +330,127 @@ void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRML
char *get_http_header_value(char *headers, char *type)
{
char *tmp = NULL,*var = NULL;
int size;
char *pos, *tmp = NULL;
int typelen, headerslen;
typelen = strlen(type);
headerslen = strlen(headers);
/* header `titles' can be lower case, or any case combination, according
* to the various RFC's. */
pos = headers;
do {
/* start of buffer or start of line */
if (strncasecmp(pos, type, typelen) == 0) {
char *eol;
/* match */
tmp = pos + typelen;
eol = strstr(tmp, "\r\n");
if (eol == NULL) {
eol = headers + headerslen;
}
return estrndup(tmp, eol - tmp);
}
/* find next line */
pos = strstr(pos, "\r\n");
if (pos)
pos += 2;
tmp = strstr(headers, type);
if(tmp != NULL)
{
tmp += strlen(type);
size = strstr(tmp, "\r\n") - tmp;
var = emalloc(size + 1);
strncpy(var, tmp, size);
var[size] = '\0';
}
return var;
} while (pos);
return NULL;
}
int get_http_body(SOAP_STREAM stream, char *headers, char **response, int *out_size TSRMLS_DC)
int get_http_body(php_stream *stream, char *headers, char **response, int *out_size TSRMLS_DC)
{
char *trans_enc, *content_length, *http_buf;
char *trans_enc, *content_length, *http_buf = NULL;
int http_buf_size = 0;
/* TSRMLS_FETCH();*/
trans_enc = get_http_header_value(headers, "Transfer-Encoding: ");
content_length = get_http_header_value(headers, "Content-Length: ");
/* this is temp...
netscape enterprise server sends in lowercase???
*/
if(content_length == NULL)
content_length = get_http_header_value(headers, "Content-length: ");
if(trans_enc && !strcmp(trans_enc, "chunked"))
{
if (trans_enc && !strcmp(trans_enc, "chunked")) {
int cur = 0, size = 0, buf_size = 0, len_size;
char done, chunk_size[10];
done = FALSE;
http_buf = emalloc(1);
*http_buf = '\0';
while(!done)
{
for (cur = 0; cur < 3 || !(chunk_size[cur - 2] == '\r' && chunk_size[cur - 1] == '\n'); cur++)
#ifdef PHP_HAVE_STREAMS
chunk_size[cur] = php_stream_getc(stream);
#else
chunk_size[cur] = php_sock_fgetc(stream);
#endif
chunk_size[cur] = '\0';
if(sscanf(chunk_size,"%x",&buf_size) != -1)
{
http_buf = erealloc(http_buf,http_buf_size + buf_size);
http_buf = NULL;
while (!done) {
php_stream_gets(stream, chunk_size, sizeof(chunk_size));
if (sscanf(chunk_size, "%x", &buf_size) != -1) {
http_buf = erealloc(http_buf, http_buf_size + buf_size + 1);
len_size = 0;
while(http_buf_size < buf_size)
{
#ifdef PHP_HAVE_STREAMS
len_size += php_stream_read(stream, &http_buf[http_buf_size], buf_size - len_size);
#else
len_size += php_sock_fread(&http_buf[http_buf_size], buf_size - len_size, stream);
#endif
while (http_buf_size < buf_size) {
len_size += php_stream_read(stream, http_buf + http_buf_size, buf_size - len_size);
http_buf_size += len_size;
}
#ifdef PHP_HAVE_STREAMS
php_stream_getc(stream);php_stream_getc(stream);
#else
/* Eat up '\r' '\n' */
php_sock_fgetc(stream);php_sock_fgetc(stream);
#endif
php_stream_getc(stream);php_stream_getc(stream);
}
if(buf_size == 0)
if (buf_size == 0) {
done = TRUE;
}
}
efree(trans_enc);
}
else if(content_length)
{
if (http_buf == NULL) {
http_buf = estrndup("", 1);
http_buf_size = 1;
} else {
http_buf[http_buf_size] = '\0';
}
} else if (content_length) {
int size;
size = atoi(content_length);
http_buf = emalloc(size + 1);
while(http_buf_size < size)
#ifdef PHP_HAVE_STREAMS
http_buf_size += php_stream_read(stream, &http_buf[http_buf_size], size - http_buf_size);
#else
http_buf_size += php_sock_fread(&http_buf[http_buf_size], size - http_buf_size, stream);
#endif
while(http_buf_size < size) {
http_buf_size += php_stream_read(stream, http_buf + http_buf_size, size - http_buf_size);
}
http_buf[size] = '\0';
efree(content_length);
} else {
php_error(E_ERROR, "Don't know how to read http body, No Content-Length or chunked data");
}
else
php_error(E_ERROR,"Don't know how to read http body, No Content-Length or chunked data");
(*response) = http_buf;
(*out_size) = http_buf_size;
return TRUE;
}
int get_http_headers(SOAP_STREAM stream, char **response, int *out_size TSRMLS_DC)
int get_http_headers(php_stream *stream, char **response, int *out_size TSRMLS_DC)
{
int done;
int done = FALSE;
char chr;
smart_str tmp_response = {0};
done = FALSE;
char headerbuf[8192];
while(!done)
{
#ifdef PHP_HAVE_STREAMS
chr = php_stream_getc(stream);
#else
chr = php_sock_fgetc(stream);
#endif
if(chr != EOF)
{
smart_str_appendc(&tmp_response, chr);
if(tmp_response.c[tmp_response.len - 2] == '\r' && tmp_response.c[tmp_response.len - 1] == '\n' &&
tmp_response.c[tmp_response.len - 4] == '\r' && tmp_response.c[tmp_response.len - 3] == '\n')
{
smart_str_0(&tmp_response);
done = TRUE;
}
} else {
return FALSE;
if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
break;
}
if (strcmp(headerbuf, "\r\n") == 0) {
/* empty line marks end of headers */
done = TRUE;
break;
}
/* add header to collection */
smart_str_appends(&tmp_response, headerbuf);
}
smart_str_0(&tmp_response);
(*response) = tmp_response.c;
(*out_size) = tmp_response.len;
return TRUE;
return done;
}
#ifndef PHP_HAVE_STREAMS
SOCKET get_socket(char* host,int portno,int time)
{
SOCKET socketd = -1;
struct sockaddr_in server;
struct timeval timeout;
memset(&server, 0, sizeof(server));
socketd = socket(AF_INET,SOCK_STREAM,0);
if (socketd == SOCK_ERR) {
if(socketd > 0)
SOCK_CLOSE(socketd);
return FALSE;
}
server.sin_family = AF_INET;
if(php_lookup_hostname(host,&server.sin_addr)) {
if(socketd > 0)
SOCK_CLOSE(socketd);
return FALSE;
}
server.sin_port = htons((unsigned short)portno);
timeout.tv_sec = time;
timeout.tv_usec = 0;
if (php_connect_nonb(socketd, (struct sockaddr *)&server, sizeof(struct sockaddr_in), &timeout) == SOCK_CONN_ERR) {
if(socketd > 0)
SOCK_CLOSE(socketd);
return FALSE;
}
return socketd;
}
#endif

18
ext/soap/php_http.h

@ -5,21 +5,7 @@ void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, ch
void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS_DC);
char *get_http_header_value(char *headers, char *type);
int get_http_body(SOAP_STREAM socketd, char *headers, char **response, int *out_size TSRMLS_DC);
int get_http_headers(SOAP_STREAM socketd,char **response, int *out_size TSRMLS_DC);
#ifndef PHP_HAVE_STREAMS
#ifndef ZEND_WIN32
# ifndef closesocket
# define closesocket close
# endif
#endif
#ifndef SOCK_CLOSE
# define SOCK_CLOSE(s) shutdown(s, 0); closesocket(s)
#endif
SOCKET get_socket(char* host,int portno,int timeout);
#endif
int get_http_body(php_stream *socketd, char *headers, char **response, int *out_size TSRMLS_DC);
int get_http_headers(php_stream *socketd,char **response, int *out_size TSRMLS_DC);
#endif

22
ext/soap/php_soap.h

@ -16,19 +16,11 @@
# include "ext/domxml/php_domxml.h"
#endif
#ifdef PHP_WIN32
# ifdef PHP_HAVE_STREAMS
# define SOAP_STREAM php_stream *
# else
# define SOAP_STREAM SOCKET
# endif
#else
# ifdef PHP_HAVE_STREAMS
# define SOAP_STREAM php_stream *
# else
# define SOCKET unsigned int
# define SOAP_STREAM SOCKET
# endif
#ifndef PHP_HAVE_STREAMS
# error You lose - must be compiled against PHP 4.3.0 or later
#endif
#ifndef PHP_WIN32
# define TRUE 1
# define FALSE 0
# define stricmp strcasecmp
@ -401,8 +393,8 @@ int my_call_user_function(HashTable *function_table, zval **object_pp, zval *fun
ss = NULL; \
}
#define FIND_SOCKET_PROPERTY(ss,tmp) zend_hash_find(Z_OBJPROP_P(ss), "httpsocket", sizeof("httpsocket"), (void **)&tmp)
#define FETCH_SOCKET_RES(ss,tmp) ss = (SOAP_STREAM)zend_fetch_resource(tmp TSRMLS_CC, -1, "httpsocket", NULL, 1, le_http_socket)
#define FIND_SOCKET_PROPERTY(ss,tmp) zend_hash_find(Z_OBJPROP_P(ss), "httpsocket", sizeof("httpsocket"), (void **)&tmp)
#define FETCH_SOCKET_RES(ss,tmp) php_stream_from_zval_no_verify(ss,tmp)
#define GET_THIS_OBJECT(o) \
o = getThis(); \

28
ext/soap/php_xml.c

@ -1,5 +1,33 @@
#include "php_soap.h"
/* Channel libxml file io layer through the PHP streams subsystem.
* This allows use of ftps:// and https:// urls */
int php_stream_xmlIO_match_wrapper(const char *filename)
{
TSRMLS_FETCH();
return php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ? 1 : 0;
}
void *php_stream_xmlIO_open_wrapper(const char *filename)
{
TSRMLS_FETCH();
return php_stream_open_wrapper(filename, "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
}
int php_stream_xmlIO_read(void *context, char *buffer, int len)
{
TSRMLS_FETCH();
return php_stream_read((php_stream*)context, buffer, len);
}
int php_stream_xmlIO_close(void *context)
{
TSRMLS_FETCH();
return php_stream_close((php_stream*)context);
}
xmlNsPtr attr_find_ns(xmlAttrPtr node)
{
if(node->ns)

5
ext/soap/php_xml.h

@ -20,4 +20,9 @@ xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, cha
int parse_namespace(char *inval,char **value,char **namespace);
xmlNodePtr check_and_resolve_href(xmlNodePtr data);
int php_stream_xmlIO_match_wrapper(const char *filename);
void *php_stream_xmlIO_open_wrapper(const char *filename);
int php_stream_xmlIO_read(void *context, char *buffer, int len);
int php_stream_xmlIO_close(void *context);
#endif

36
ext/soap/soap.c

@ -1,7 +1,6 @@
#include "php_soap.h"
int le_sdl = 0;
int le_http_socket = 0;
int le_url = 0;
int le_service = 0;
@ -185,6 +184,11 @@ PHP_MINIT_FUNCTION(soap)
/* TODO: add ini entry for always use soap errors */
ZEND_INIT_MODULE_GLOBALS(soap, php_soap_init_globals, php_soap_del_globals);
/* Enable php stream/wrapper support for libxml */
xmlRegisterDefaultInputCallbacks();
xmlRegisterInputCallbacks(php_stream_xmlIO_match_wrapper, php_stream_xmlIO_open_wrapper,
php_stream_xmlIO_read, php_stream_xmlIO_close);
/* Register SoapObject class */
/* BIG NOTE : THIS EMITS AN COMPILATION WARNING UNDER ZE2 - handle_function_call deprecated.
soap_call_function_handler should be of type struct _zend_function, not (*handle_function_call).
@ -209,7 +213,6 @@ PHP_MINIT_FUNCTION(soap)
zend_register_internal_class(&soap_param_class_entry TSRMLS_CC);
le_sdl = register_list_destructors(NULL, NULL);
le_http_socket = register_list_destructors(delete_http_socket, NULL);
le_url = register_list_destructors(delete_url, NULL);
le_service = register_list_destructors(delete_service, NULL);
@ -781,6 +784,8 @@ PHP_FUNCTION(addfunction)
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &function_name) == FAILURE)
php_error(E_ERROR, "Invalid parameters passed to addfunction");
/* TODO: could use zend_is_callable here */
if(function_name->type == IS_ARRAY)
{
if(service->type == SOAP_FUNCTIONS)
@ -1167,6 +1172,7 @@ PHP_FUNCTION(soapobject)
ret = zend_list_insert(sdl, le_sdl);
add_property_resource(thisObj, "sdl", ret);
/* FIXME: this is extremely bad practice */
add_property_resource(thisObj, "port", (long)get_binding_from_type(sdl, BINDING_SOAP));
zend_list_addref(ret);
}
@ -1261,7 +1267,7 @@ PHP_FUNCTION(__generate)
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|ss",
&function, &function_len, &args, &soap_action, &soap_action_len, &uri, &uri_len) == FAILURE)
php_error(E_ERROR, "Invalid arguments to SoapObject->__call");
php_error(E_ERROR, "Invalid arguments to SoapObject->__generate");
arg_count = zend_hash_num_elements(Z_ARRVAL_P(args));
@ -1331,6 +1337,7 @@ PHP_FUNCTION(__parse)
}
if (ret_params) {
FREE_ZVAL(ret_params[0]);
efree(ret_params);
}
}
@ -1381,6 +1388,7 @@ PHP_FUNCTION(__call)
}
if (ret_params) {
FREE_ZVAL(ret_params[0]);
efree(ret_params);
}
}
@ -1482,9 +1490,7 @@ PHP_FUNCTION(__getlastrequest)
if(zend_hash_find(Z_OBJPROP_P(thisObj), "__last_request", sizeof("__last_request"), (void **)&tmp) == SUCCESS)
{
*return_value = *(*tmp);
zval_copy_ctor(return_value);
return;
RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
}
RETURN_NULL();
}
@ -1498,9 +1504,7 @@ PHP_FUNCTION(__getlastresponse)
if(zend_hash_find(Z_OBJPROP_P(thisObj), "__last_response", sizeof("__last_response"), (void **)&tmp) == SUCCESS)
{
*return_value = *(*tmp);
zval_copy_ctor(return_value);
return;
RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
}
RETURN_NULL();
}
@ -1512,8 +1516,6 @@ void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_refe
zval *thisObj;
char *function = Z_STRVAL(function_name->element);
zend_function *builtin_function;
// TSRMLS_FETCH();
GET_THIS_OBJECT(thisObj);
@ -1578,6 +1580,7 @@ void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_refe
}
if (ret_params) {
FREE_ZVAL(ret_params[0]);
efree(ret_params);
}
}
@ -2116,17 +2119,6 @@ void delete_sdl(void *handle)
free(tmp);
}
void delete_http_socket(void *handle)
{
SOAP_STREAM stream = (SOAP_STREAM)handle;
#ifdef PHP_HAVE_STREAMS
TSRMLS_FETCH();
php_stream_close(stream);
#else
SOCK_CLOSE(stream);
#endif
}
void delete_url(void *handle)
{
php_url_free((php_url*)handle);

Loading…
Cancel
Save