Annotation of embedaddon/php/ext/curl/streams.c, revision 1.1.1.2

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: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      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) {
1.1.1.2 ! misho     398:                                if (PG(open_basedir) && *PG(open_basedir)) {
1.1       misho     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 {
1.1.1.2 ! misho     406:                        if (PG(open_basedir) && *PG(open_basedir)) {
1.1       misho     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>