Annotation of embedaddon/php/ext/curl/streams.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: Wez Furlong <wez@thebrainroom.com> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: streams.c 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: /* This file implements cURL based wrappers.
! 22: * NOTE: If you are implementing your own streams that are intended to
! 23: * work independently of wrappers, this is not a good example to follow!
! 24: **/
! 25:
! 26: #ifdef HAVE_CONFIG_H
! 27: #include "config.h"
! 28: #endif
! 29:
! 30: #include "php.h"
! 31: #include "php_memory_streams.h"
! 32:
! 33: #if HAVE_CURL
! 34:
! 35: #include <stdio.h>
! 36: #include <string.h>
! 37:
! 38: #ifdef PHP_WIN32
! 39: #include <winsock2.h>
! 40: #include <sys/types.h>
! 41: #endif
! 42:
! 43: #include <curl/curl.h>
! 44: #include <curl/easy.h>
! 45:
! 46: #define SMART_STR_PREALLOC 4096
! 47:
! 48: #include "ext/standard/php_smart_str.h"
! 49: #include "ext/standard/info.h"
! 50: #include "ext/standard/file.h"
! 51: #include "ext/standard/php_string.h"
! 52: #include "php_curl.h"
! 53:
! 54: static size_t on_data_available(char *data, size_t size, size_t nmemb, void *ctx)
! 55: {
! 56: php_stream *stream = (php_stream *) ctx;
! 57: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 58: size_t wrote;
! 59: TSRMLS_FETCH();
! 60:
! 61: /* TODO: I'd like to deprecate this.
! 62: * This code is here because until we start getting real data, we don't know
! 63: * if we have had all of the headers
! 64: * */
! 65: if (curlstream->readbuffer.writepos == 0) {
! 66: zval *sym;
! 67:
! 68: if (!EG(active_symbol_table)) {
! 69: zend_rebuild_symbol_table(TSRMLS_C);
! 70: }
! 71: MAKE_STD_ZVAL(sym);
! 72: *sym = *curlstream->headers;
! 73: zval_copy_ctor(sym);
! 74: ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", sym);
! 75: }
! 76:
! 77: php_stream_seek(curlstream->readbuffer.buf, curlstream->readbuffer.writepos, SEEK_SET);
! 78: wrote = php_stream_write(curlstream->readbuffer.buf, data, size * nmemb);
! 79: curlstream->readbuffer.writepos = php_stream_tell(curlstream->readbuffer.buf);
! 80:
! 81: return wrote;
! 82: }
! 83:
! 84: /* cURL guarantees that headers are written as complete lines, with this function
! 85: * called once for each header */
! 86: static size_t on_header_available(char *data, size_t size, size_t nmemb, void *ctx)
! 87: {
! 88: size_t length = size * nmemb;
! 89: zval *header;
! 90: php_stream *stream = (php_stream *) ctx;
! 91: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 92: TSRMLS_FETCH();
! 93:
! 94: if (length < 2) {
! 95: /* invalid header ? */
! 96: return length;
! 97: }
! 98:
! 99: if (!(length == 2 && data[0] == '\r' && data[1] == '\n')) {
! 100: MAKE_STD_ZVAL(header);
! 101: Z_STRLEN_P(header) = length;
! 102: Z_STRVAL_P(header) = estrndup(data, length);
! 103: if (Z_STRVAL_P(header)[length-1] == '\n') {
! 104: Z_STRVAL_P(header)[length-1] = '\0';
! 105: Z_STRLEN_P(header)--;
! 106:
! 107: if (Z_STRVAL_P(header)[length-2] == '\r') {
! 108: Z_STRVAL_P(header)[length-2] = '\0';
! 109: Z_STRLEN_P(header)--;
! 110: }
! 111: }
! 112: Z_TYPE_P(header) = IS_STRING;
! 113: zend_hash_next_index_insert(Z_ARRVAL_P(curlstream->headers), &header, sizeof(zval *), NULL);
! 114:
! 115: /* based on the header, we might need to trigger a notification */
! 116: if (!strncasecmp(data, "Location: ", 10)) {
! 117: php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_REDIRECTED, data + 10, 0);
! 118: } else if (!strncasecmp(data, "Content-Type: ", 14)) {
! 119: php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, data + 14, 0);
! 120: } else if (!strncasecmp(data, "Context-Length: ", 16)) {
! 121: php_stream_notify_file_size(stream->context, atoi(data + 16), data, 0);
! 122: php_stream_notify_progress_init(stream->context, 0, 0);
! 123: }
! 124: }
! 125: return length;
! 126:
! 127: }
! 128:
! 129: static int on_progress_avail(php_stream *stream, double dltotal, double dlnow, double ultotal, double ulnow)
! 130: {
! 131: TSRMLS_FETCH();
! 132:
! 133: /* our notification system only works in a single direction; we should detect which
! 134: * direction is important and use the correct values in this call */
! 135: php_stream_notify_progress(stream->context, (size_t) dlnow, (size_t) dltotal);
! 136: return 0;
! 137: }
! 138:
! 139: static size_t php_curl_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
! 140: {
! 141: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 142:
! 143: if (curlstream->writebuffer.buf) {
! 144: return php_stream_write(curlstream->writebuffer.buf, buf, count);
! 145: }
! 146:
! 147: return 0;
! 148: }
! 149:
! 150: static size_t php_curl_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
! 151: {
! 152: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 153: size_t didread = 0;
! 154:
! 155: if (curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending) {
! 156: /* we need to read some more data */
! 157: struct timeval tv;
! 158:
! 159: /* fire up the connection */
! 160: if (curlstream->readbuffer.writepos == 0) {
! 161: while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlstream->multi, &curlstream->pending));
! 162: }
! 163:
! 164: do {
! 165: /* get the descriptors from curl */
! 166: curl_multi_fdset(curlstream->multi, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &curlstream->maxfd);
! 167:
! 168: /* if we are in blocking mode, set a timeout */
! 169: tv.tv_usec = 0;
! 170: tv.tv_sec = 15; /* TODO: allow this to be configured from the script */
! 171:
! 172: /* wait for data */
! 173: switch ((curlstream->maxfd < 0) ? 1 :
! 174: select(curlstream->maxfd + 1, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &tv)) {
! 175: case -1:
! 176: /* error */
! 177: return 0;
! 178: case 0:
! 179: /* no data yet: timed-out */
! 180: return 0;
! 181: default:
! 182: /* fetch the data */
! 183: do {
! 184: curlstream->mcode = curl_multi_perform(curlstream->multi, &curlstream->pending);
! 185: } while (curlstream->mcode == CURLM_CALL_MULTI_PERFORM);
! 186: }
! 187: } while (curlstream->maxfd >= 0 &&
! 188: curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending > 0);
! 189:
! 190: }
! 191:
! 192: /* if there is data in the buffer, try and read it */
! 193: if (curlstream->readbuffer.writepos > 0 && curlstream->readbuffer.readpos < curlstream->readbuffer.writepos) {
! 194: php_stream_seek(curlstream->readbuffer.buf, curlstream->readbuffer.readpos, SEEK_SET);
! 195: didread = php_stream_read(curlstream->readbuffer.buf, buf, count);
! 196: curlstream->readbuffer.readpos = php_stream_tell(curlstream->readbuffer.buf);
! 197: }
! 198:
! 199: if (didread == 0) {
! 200: stream->eof = 1;
! 201: }
! 202:
! 203: return didread;
! 204: }
! 205:
! 206: static int php_curl_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
! 207: {
! 208: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 209:
! 210: /* TODO: respect the close_handle flag here, so that casting to a FILE* on
! 211: * systems without fopencookie will work properly */
! 212:
! 213: curl_multi_remove_handle(curlstream->multi, curlstream->curl);
! 214: curl_easy_cleanup(curlstream->curl);
! 215: curl_multi_cleanup(curlstream->multi);
! 216:
! 217: /* we are not closing curlstream->readbuf here, because we export
! 218: * it as a zval with the wrapperdata - the engine will garbage collect it */
! 219:
! 220: efree(curlstream->url);
! 221: efree(curlstream);
! 222:
! 223: return 0;
! 224: }
! 225:
! 226: static int php_curl_stream_flush(php_stream *stream TSRMLS_DC)
! 227: {
! 228: #ifdef ilia_0
! 229: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 230: #endif
! 231: return 0;
! 232: }
! 233:
! 234: static int php_curl_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
! 235: {
! 236: /* TODO: fill in details based on Data: and Content-Length: headers, and/or data
! 237: * from curl_easy_getinfo().
! 238: * For now, return -1 to indicate that it doesn't make sense to stat this stream */
! 239: return -1;
! 240: }
! 241:
! 242: static int php_curl_stream_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
! 243: {
! 244: php_curl_stream *curlstream = (php_curl_stream *) stream->abstract;
! 245: /* delegate to the readbuffer stream */
! 246: return php_stream_cast(curlstream->readbuffer.buf, castas, ret, 0);
! 247: }
! 248:
! 249: php_stream_ops php_curl_stream_ops = {
! 250: php_curl_stream_write,
! 251: php_curl_stream_read,
! 252: php_curl_stream_close,
! 253: php_curl_stream_flush,
! 254: "cURL",
! 255: NULL, /* seek */
! 256: php_curl_stream_cast, /* cast */
! 257: php_curl_stream_stat /* stat */
! 258: };
! 259:
! 260:
! 261: php_stream *php_curl_stream_opener(php_stream_wrapper *wrapper, char *filename, char *mode,
! 262: int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
! 263: {
! 264: php_stream *stream;
! 265: php_curl_stream *curlstream;
! 266: zval *tmp, **ctx_opt = NULL;
! 267: struct curl_slist *slist = NULL;
! 268:
! 269: curlstream = emalloc(sizeof(php_curl_stream));
! 270: memset(curlstream, 0, sizeof(php_curl_stream));
! 271:
! 272: stream = php_stream_alloc(&php_curl_stream_ops, curlstream, 0, mode);
! 273: php_stream_context_set(stream, context);
! 274:
! 275: curlstream->curl = curl_easy_init();
! 276: curlstream->multi = curl_multi_init();
! 277: curlstream->pending = 1;
! 278:
! 279: /* if opening for an include statement, ensure that the local storage will
! 280: * have a FILE* associated with it.
! 281: * Otherwise, use the "smart" memory stream that will turn itself into a file
! 282: * when it gets large */
! 283: #ifndef HAVE_FOPENCOOKIE
! 284: if (options & STREAM_WILL_CAST) {
! 285: curlstream->readbuffer.buf = php_stream_fopen_tmpfile();
! 286: } else
! 287: #endif
! 288: {
! 289: curlstream->readbuffer.buf = php_stream_temp_new();
! 290: }
! 291:
! 292: /* curl requires the URL to be valid throughout it's operation, so dup it */
! 293: curlstream->url = estrdup(filename);
! 294: curl_easy_setopt(curlstream->curl, CURLOPT_URL, curlstream->url);
! 295:
! 296: /* feed curl data into our read buffer */
! 297: curl_easy_setopt(curlstream->curl, CURLOPT_WRITEFUNCTION, on_data_available);
! 298: curl_easy_setopt(curlstream->curl, CURLOPT_FILE, stream);
! 299:
! 300: /* feed headers */
! 301: curl_easy_setopt(curlstream->curl, CURLOPT_HEADERFUNCTION, on_header_available);
! 302: curl_easy_setopt(curlstream->curl, CURLOPT_WRITEHEADER, stream);
! 303:
! 304: curl_easy_setopt(curlstream->curl, CURLOPT_ERRORBUFFER, curlstream->errstr);
! 305: curl_easy_setopt(curlstream->curl, CURLOPT_VERBOSE, 0);
! 306:
! 307: /* enable progress notification */
! 308: curl_easy_setopt(curlstream->curl, CURLOPT_PROGRESSFUNCTION, on_progress_avail);
! 309: curl_easy_setopt(curlstream->curl, CURLOPT_PROGRESSDATA, stream);
! 310: curl_easy_setopt(curlstream->curl, CURLOPT_NOPROGRESS, 0);
! 311:
! 312: curl_easy_setopt(curlstream->curl, CURLOPT_USERAGENT, FG(user_agent) ? FG(user_agent) : "PHP/" PHP_VERSION);
! 313:
! 314: /* TODO: read cookies and options from context */
! 315: if (context && !strncasecmp(filename, "http", sizeof("http")-1)) {
! 316: /* Protocol version */
! 317: if (SUCCESS == php_stream_context_get_option(context, "http", "protocol_version", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_DOUBLE) {
! 318: if (Z_DVAL_PP(ctx_opt) == 1.1) {
! 319: curl_easy_setopt(curlstream->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
! 320: } else {
! 321: curl_easy_setopt(curlstream->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
! 322: }
! 323: }
! 324:
! 325: if (SUCCESS == php_stream_context_get_option(context, "http", "curl_verify_ssl_host", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
! 326: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 1);
! 327: } else {
! 328: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 0);
! 329: }
! 330: if (SUCCESS == php_stream_context_get_option(context, "http", "curl_verify_ssl_peer", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
! 331: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 1);
! 332: } else {
! 333: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 0);
! 334: }
! 335:
! 336: /* HTTP(S) */
! 337: if (SUCCESS == php_stream_context_get_option(context, "http", "user_agent", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
! 338: curl_easy_setopt(curlstream->curl, CURLOPT_USERAGENT, Z_STRVAL_PP(ctx_opt));
! 339: }
! 340: if (SUCCESS == php_stream_context_get_option(context, "http", "header", &ctx_opt)) {
! 341: if (Z_TYPE_PP(ctx_opt) == IS_ARRAY) {
! 342: HashPosition pos;
! 343: zval **header = NULL;
! 344:
! 345: for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(ctx_opt), &pos);
! 346: SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(ctx_opt), (void *)&header, &pos);
! 347: zend_hash_move_forward_ex(Z_ARRVAL_PP(ctx_opt), &pos)
! 348: ) {
! 349: if (Z_TYPE_PP(header) == IS_STRING) {
! 350: slist = curl_slist_append(slist, Z_STRVAL_PP(header));
! 351: }
! 352: }
! 353: } else if (Z_TYPE_PP(ctx_opt) == IS_STRING && Z_STRLEN_PP(ctx_opt)) {
! 354: char *p, *token, *trimmed, *copy_ctx_opt;
! 355:
! 356: copy_ctx_opt = php_trim(Z_STRVAL_PP(ctx_opt), Z_STRLEN_PP(ctx_opt), NULL, 0, NULL, 3 TSRMLS_CC);
! 357: p = php_strtok_r(copy_ctx_opt, "\r\n", &token);
! 358: while (p) {
! 359: trimmed = php_trim(p, strlen(p), NULL, 0, NULL, 3 TSRMLS_CC);
! 360: slist = curl_slist_append(slist, trimmed);
! 361: efree(trimmed);
! 362: p = php_strtok_r(NULL, "\r\n", &token);
! 363: }
! 364: efree(copy_ctx_opt);
! 365: }
! 366: if (slist) {
! 367: curl_easy_setopt(curlstream->curl, CURLOPT_HTTPHEADER, slist);
! 368: }
! 369: }
! 370: if (SUCCESS == php_stream_context_get_option(context, "http", "method", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
! 371: if (strcasecmp(Z_STRVAL_PP(ctx_opt), "get")) {
! 372: if (!strcasecmp(Z_STRVAL_PP(ctx_opt), "head")) {
! 373: curl_easy_setopt(curlstream->curl, CURLOPT_NOBODY, 1);
! 374: } else {
! 375: if (!strcasecmp(Z_STRVAL_PP(ctx_opt), "post")) {
! 376: curl_easy_setopt(curlstream->curl, CURLOPT_POST, 1);
! 377: } else {
! 378: curl_easy_setopt(curlstream->curl, CURLOPT_CUSTOMREQUEST, Z_STRVAL_PP(ctx_opt));
! 379: }
! 380: if (SUCCESS == php_stream_context_get_option(context, "http", "content", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
! 381: curl_easy_setopt(curlstream->curl, CURLOPT_POSTFIELDS, Z_STRVAL_PP(ctx_opt));
! 382: curl_easy_setopt(curlstream->curl, CURLOPT_POSTFIELDSIZE, (long)Z_STRLEN_PP(ctx_opt));
! 383: }
! 384: }
! 385: }
! 386: }
! 387: if (SUCCESS == php_stream_context_get_option(context, "http", "proxy", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_STRING) {
! 388: curl_easy_setopt(curlstream->curl, CURLOPT_PROXY, Z_STRVAL_PP(ctx_opt));
! 389: }
! 390: if (SUCCESS == php_stream_context_get_option(context, "http", "max_redirects", &ctx_opt)) {
! 391: long mr = 20;
! 392: if (Z_TYPE_PP(ctx_opt) != IS_STRING || !is_numeric_string(Z_STRVAL_PP(ctx_opt), Z_STRLEN_PP(ctx_opt), &mr, NULL, 1)) {
! 393: if (Z_TYPE_PP(ctx_opt) == IS_LONG) {
! 394: mr = Z_LVAL_PP(ctx_opt);
! 395: }
! 396: }
! 397: if (mr > 1) {
! 398: if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) {
! 399: curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 0);
! 400: } else {
! 401: curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 1);
! 402: }
! 403: curl_easy_setopt(curlstream->curl, CURLOPT_MAXREDIRS, mr);
! 404: }
! 405: } else {
! 406: if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) {
! 407: curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 0);
! 408: } else {
! 409: curl_easy_setopt(curlstream->curl, CURLOPT_FOLLOWLOCATION, 1);
! 410: }
! 411: curl_easy_setopt(curlstream->curl, CURLOPT_MAXREDIRS, 20L);
! 412: }
! 413: } else if (context && !strncasecmp(filename, "ftps", sizeof("ftps")-1)) {
! 414: if (SUCCESS == php_stream_context_get_option(context, "ftp", "curl_verify_ssl_host", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
! 415: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 1);
! 416: } else {
! 417: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYHOST, 0);
! 418: }
! 419: if (SUCCESS == php_stream_context_get_option(context, "ftp", "curl_verify_ssl_peer", &ctx_opt) && Z_TYPE_PP(ctx_opt) == IS_BOOL && Z_LVAL_PP(ctx_opt) == 1) {
! 420: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 1);
! 421: } else {
! 422: curl_easy_setopt(curlstream->curl, CURLOPT_SSL_VERIFYPEER, 0);
! 423: }
! 424: }
! 425:
! 426: /* prepare for "pull" mode */
! 427: curl_multi_add_handle(curlstream->multi, curlstream->curl);
! 428:
! 429: /* Prepare stuff for file_get_wrapper_data: the data is an array:
! 430: *
! 431: * data = array(
! 432: * "headers" => array("Content-Type: text/html", "Xxx: Yyy"),
! 433: * "readbuf" => resource (equivalent to curlstream->readbuffer)
! 434: * );
! 435: * */
! 436: MAKE_STD_ZVAL(stream->wrapperdata);
! 437: array_init(stream->wrapperdata);
! 438:
! 439: MAKE_STD_ZVAL(curlstream->headers);
! 440: array_init(curlstream->headers);
! 441:
! 442: add_assoc_zval(stream->wrapperdata, "headers", curlstream->headers);
! 443:
! 444: MAKE_STD_ZVAL(tmp);
! 445: php_stream_to_zval(curlstream->readbuffer.buf, tmp);
! 446: add_assoc_zval(stream->wrapperdata, "readbuf", tmp);
! 447:
! 448: #ifndef HAVE_FOPENCOOKIE
! 449: if (options & STREAM_WILL_CAST) {
! 450: /* we will need to download the whole resource now,
! 451: * since we cannot get the actual FD for the download,
! 452: * so we won't be able to drive curl via stdio. */
! 453:
! 454: /* TODO: this needs finishing */
! 455:
! 456: curl_easy_perform(curlstream->curl);
! 457: }
! 458: else
! 459: #endif
! 460: {
! 461: /* fire up the connection; we need to detect a connection error here,
! 462: * otherwise the curlstream we return ends up doing nothing useful. */
! 463: CURLMcode m;
! 464: CURLMsg *msg;
! 465: int msgs_left, msg_found = 0;
! 466:
! 467: while (CURLM_CALL_MULTI_PERFORM == (m = curl_multi_perform(curlstream->multi, &curlstream->pending))) {
! 468: ; /* spin */
! 469: }
! 470:
! 471: if (m != CURLM_OK) {
! 472: #if HAVE_CURL_MULTI_STRERROR
! 473: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(m));
! 474: #else
! 475: php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error mcode=%d", m);
! 476: #endif
! 477: goto exit_fail;
! 478: }
! 479:
! 480: /* we have only one curl handle here, even though we use multi syntax,
! 481: * so it's ok to fail on any error */
! 482: while ((msg = curl_multi_info_read(curlstream->multi, &msgs_left))) {
! 483: if (msg->data.result == CURLE_OK) {
! 484: continue;
! 485: } else {
! 486: #if HAVE_CURL_EASY_STRERROR
! 487: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_easy_strerror(msg->data.result));
! 488: #else
! 489: php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error mcode=%d", msg->data.result);
! 490: #endif
! 491: msg_found++;
! 492: }
! 493: }
! 494: if (msg_found) {
! 495: goto exit_fail;
! 496: }
! 497: }
! 498:
! 499: /* context headers are not needed anymore */
! 500: if (slist) {
! 501: curl_easy_setopt(curlstream->curl, CURLOPT_HTTPHEADER, NULL);
! 502: curl_slist_free_all(slist);
! 503: }
! 504: return stream;
! 505:
! 506: exit_fail:
! 507: php_stream_close(stream);
! 508: if (slist) {
! 509: curl_slist_free_all(slist);
! 510: }
! 511: return NULL;
! 512: }
! 513:
! 514: static php_stream_wrapper_ops php_curl_wrapper_ops = {
! 515: php_curl_stream_opener,
! 516: NULL, /* stream_close: curl streams know how to clean themselves up */
! 517: NULL, /* stream_stat: curl streams know how to stat themselves */
! 518: NULL, /* stat url */
! 519: NULL, /* opendir */
! 520: "cURL", /* label */
! 521: NULL, /* unlink */
! 522: NULL, /* rename */
! 523: NULL, /* mkdir */
! 524: NULL /* rmdir */
! 525: };
! 526:
! 527: php_stream_wrapper php_curl_wrapper = {
! 528: &php_curl_wrapper_ops,
! 529: NULL,
! 530: 1 /* is_url */
! 531: };
! 532:
! 533: #endif
! 534:
! 535: /*
! 536: * Local variables:
! 537: * tab-width: 4
! 538: * c-basic-offset: 4
! 539: * End:
! 540: * vim600: noet sw=4 ts=4 fdm=marker
! 541: * vim<600: noet sw=4 ts=4
! 542: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>