LCOV - code coverage report
Current view: top level - common/stream - url_stream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 99 0.0 %
Date: 2024-04-25 20:03:45 Functions: 0 6 0.0 %

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

Generated by: LCOV version 1.14