LCOV - code coverage report
Current view: top level - common/stream - url_stream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 88 0.0 %
Date: 2021-10-27 03:06:47 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /* streams working on a gzip-compressed disk file */
      10             : 
      11             : #include "monetdb_config.h"
      12             : #include "stream.h"
      13             : #include "stream_internal.h"
      14             : 
      15             : 
      16             : 
      17             : /* ------------------------------------------------------------------ */
      18             : /* streams working on a remote file using cURL */
      19             : 
      20             : #ifdef HAVE_CURL
      21             : #include <curl/curl.h>
      22             : 
      23             : struct curl_data {
      24             :         CURL *handle;
      25             :         char *buffer;           /* buffer to store incoming data */
      26             :         size_t maxsize;         /* size of allocated buffer */
      27             :         size_t usesize;         /* end of used data */
      28             :         size_t offset;          /* start of unread data */
      29             :         int running;            /* whether still transferring */
      30             :         char errbuf[CURL_ERROR_SIZE]; /* a place for error messages */
      31             : };
      32             : 
      33             : #define BLOCK_CURL      ((size_t) 1 << 16)
      34             : 
      35             : /* this function is called by libcurl when there is data for us */
      36             : static size_t
      37           0 : write_callback(char *buffer, size_t size, size_t nitems, void *userp)
      38             : {
      39             :         stream *s = (stream *) userp;
      40           0 :         struct curl_data *c = (struct curl_data *) s->stream_data.p;
      41             : 
      42           0 :         size *= nitems;
      43           0 :         if (size == 0)          /* unlikely */
      44             :                 return 0;
      45             :         /* allocate a buffer if we don't have one yet */
      46           0 :         if (c->buffer == NULL) {
      47             :                 /* BLOCK_CURL had better be a power of 2! */
      48           0 :                 c->maxsize = (size + BLOCK_CURL - 1) & ~(BLOCK_CURL - 1);
      49           0 :                 if ((c->buffer = malloc(c->maxsize)) == NULL)
      50             :                         return 0;
      51           0 :                 c->usesize = 0;
      52           0 :                 c->offset = 0;
      53             :         }
      54             :         /* move data if we don't have enough space */
      55           0 :         if (c->maxsize - c->usesize < size && c->offset > 0) {
      56           0 :                 memmove(c->buffer, c->buffer + c->offset, c->usesize - c->offset);
      57           0 :                 c->usesize -= c->offset;
      58           0 :                 c->offset = 0;
      59             :         }
      60             :         /* allocate more buffer space if we still don't have enough space */
      61           0 :         if (c->maxsize - c->usesize < size) {
      62             :                 char *b;
      63             :                 size_t maxsize;
      64             : 
      65           0 :                 maxsize = (c->usesize + size + BLOCK_CURL - 1) & ~(BLOCK_CURL - 1);
      66           0 :                 b = realloc(c->buffer, maxsize);
      67           0 :                 if (b == NULL)
      68             :                         return 0;       /* indicate failure to library */
      69           0 :                 c->buffer = b;
      70           0 :                 c->maxsize = maxsize;
      71             :         }
      72             :         /* finally, store the data we received */
      73           0 :         memcpy(c->buffer + c->usesize, buffer, size);
      74           0 :         c->usesize += size;
      75           0 :         return size;
      76             : }
      77             : 
      78             : static void
      79           0 : curl_destroy(stream *s)
      80             : {
      81             :         struct curl_data *c;
      82             : 
      83           0 :         if ((c = (struct curl_data *) s->stream_data.p) != NULL) {
      84           0 :                 s->stream_data.p = NULL;
      85           0 :                 if (c->handle) {
      86           0 :                         curl_easy_cleanup(c->handle);
      87             :                 }
      88           0 :                 if (c->buffer)
      89           0 :                         free(c->buffer);
      90           0 :                 free(c);
      91             :         }
      92           0 :         destroy_stream(s);
      93           0 : }
      94             : 
      95             : static ssize_t
      96           0 : curl_read(stream *restrict s, void *restrict buf, size_t elmsize, size_t cnt)
      97             : {
      98           0 :         struct curl_data *c = (struct curl_data *) s->stream_data.p;
      99           0 :         size_t size = cnt * elmsize;
     100             : 
     101           0 :         if (c == NULL) {
     102           0 :                 mnstr_set_error(s, MNSTR_READ_ERROR, "stream already ended");
     103           0 :                 return -1;
     104             :         }
     105             : 
     106           0 :         if (size == 0)
     107             :                 return 0;
     108           0 :         if (c->usesize - c->offset >= elmsize || !c->running) {
     109             :                 /* there is at least one element's worth of data
     110             :                  * available, or we have reached the end: return as
     111             :                  * much as we have, but no more than requested */
     112           0 :                 if (size > c->usesize - c->offset) {
     113           0 :                         cnt = (c->usesize - c->offset) / elmsize;
     114           0 :                         size = cnt * elmsize;
     115             :                 }
     116           0 :                 memcpy(buf, c->buffer + c->offset, size);
     117           0 :                 c->offset += size;
     118           0 :                 if (c->offset == c->usesize)
     119           0 :                         c->usesize = c->offset = 0;
     120           0 :                 return (ssize_t) cnt;
     121             :         }
     122             :         /* not enough data, we must wait until we get some */
     123             :         return 0;
     124             : }
     125             : 
     126             : static ssize_t
     127           0 : curl_write(stream *restrict s, const void *restrict buf, size_t elmsize, size_t cnt)
     128             : {
     129             :         (void) s;
     130             :         (void) buf;
     131             :         (void) elmsize;
     132             :         (void) cnt;
     133           0 :         assert(0);
     134             :         return -1;
     135             : }
     136             : 
     137             : static void
     138           0 : curl_close(stream *s)
     139             : {
     140             :         (void) s;
     141           0 : }
     142             : 
     143             : stream *
     144           0 : open_urlstream(const char *url)
     145             : {
     146             :         stream *s;
     147             :         struct curl_data *c;
     148             : 
     149           0 :         if ((c = malloc(sizeof(*c))) == NULL) {
     150           0 :                 mnstr_set_open_error(url, errno, NULL);
     151           0 :                 return NULL;
     152             :         }
     153           0 :         *c = (struct curl_data) {
     154             :                 .running = 1,
     155             :                 .errbuf = {0},
     156             :         };
     157           0 :         if ((s = create_stream(url)) == NULL) {
     158           0 :                 free(c);
     159           0 :                 return NULL;
     160             :         }
     161           0 :         s->read = curl_read;
     162           0 :         s->write = curl_write;
     163           0 :         s->close = curl_close;
     164           0 :         s->destroy = curl_destroy;
     165           0 :         if ((c->handle = curl_easy_init()) == NULL) {
     166           0 :                 free(c);
     167           0 :                 destroy_stream(s);
     168           0 :                 mnstr_set_open_error(url, 0, "curl_easy_init failed");
     169           0 :                 return NULL;
     170             :         }
     171           0 :         s->stream_data.p = (void *) c;
     172           0 :         curl_easy_setopt(c->handle, CURLOPT_URL, s->name);
     173           0 :         curl_easy_setopt(c->handle, CURLOPT_WRITEDATA, s);
     174           0 :         curl_easy_setopt(c->handle, CURLOPT_VERBOSE, 0);
     175           0 :         curl_easy_setopt(c->handle, CURLOPT_NOSIGNAL, 1);
     176           0 :         curl_easy_setopt(c->handle, CURLOPT_FAILONERROR, 1);
     177           0 :         curl_easy_setopt(c->handle, CURLOPT_ERRORBUFFER, c->errbuf);
     178           0 :         curl_easy_setopt(c->handle, CURLOPT_WRITEFUNCTION, write_callback);
     179           0 :         CURLcode ret = curl_easy_perform(c->handle);
     180           0 :         if (ret != CURLE_OK) {
     181           0 :                 if (strlen(c->errbuf) > 0)
     182           0 :                         mnstr_set_open_error(url, 0, "%s", c->errbuf);
     183             :                 else
     184           0 :                         mnstr_set_open_error(url, 0, "curl_easy_perform: %s", curl_easy_strerror(ret));
     185           0 :                 curl_destroy(s);
     186           0 :                 return NULL;
     187             :         }
     188           0 :         curl_easy_cleanup(c->handle);
     189           0 :         c->handle = NULL;
     190           0 :         c->running = 0;
     191           0 :         return s;
     192             : }
     193             : 
     194             : #else
     195             : stream *
     196             : open_urlstream(const char *url)
     197             : {
     198             :         if (url != NULL &&
     199             :             strncmp(url, "file://", sizeof("file://") - 1) == 0) {
     200             :                 url +=sizeof("file://") - 1;
     201             : #ifdef _MSC_VER
     202             :                 /* file:///C:/... -- remove third / as well */
     203             :                 if (url[0] == '/' && url[2] == ':')
     204             :                         url++;
     205             : #endif
     206             :                 return open_rastream(url);
     207             :         }
     208             :         mnstr_set_open_error(url, 0, "Remote URL support has been left out of this MonetDB");
     209             :         return NULL;
     210             : }
     211             : #endif /* HAVE_CURL */

Generated by: LCOV version 1.14