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>