gnupg/keyserver/curl-shim.c

383 lines
8.0 KiB
C
Raw Normal View History

2006-06-30 15:19:49 +02:00
/* curl-shim.c - Implement a small subset of the curl API in terms of
* the iobuf HTTP API
*
* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
2006-06-30 15:19:49 +02:00
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
2007-07-04 21:49:40 +02:00
* the Free Software Foundation; either version 3 of the License, or
2006-06-30 15:19:49 +02:00
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
2007-07-04 21:49:40 +02:00
* along with this program; if not, see <http://www.gnu.org/licenses/>.
2006-06-30 15:19:49 +02:00
*/
#include <config.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
2006-06-30 15:19:49 +02:00
#include "util.h"
#include "http.h"
2006-06-30 15:19:49 +02:00
#include "ksutil.h"
#include "curl-shim.h"
static CURLcode
handle_error(CURL *curl,CURLcode err,const char *str)
{
if(curl->errorbuffer)
{
/* Make sure you never exceed CURL_ERROR_SIZE, currently set to
256 in curl-shim.h */
switch(err)
{
case CURLE_OK:
strcpy(curl->errorbuffer,"okay");
break;
case CURLE_UNSUPPORTED_PROTOCOL:
strcpy(curl->errorbuffer,"unsupported protocol");
break;
case CURLE_COULDNT_CONNECT:
strcpy(curl->errorbuffer,"couldn't connect");
break;
case CURLE_WRITE_ERROR:
strcpy(curl->errorbuffer,"write error");
break;
case CURLE_HTTP_RETURNED_ERROR:
sprintf(curl->errorbuffer,"url returned error %u",curl->status);
break;
default:
strcpy(curl->errorbuffer,"generic error");
break;
}
if(str && (strlen(curl->errorbuffer)+2+strlen(str)+1)<=CURL_ERROR_SIZE)
{
strcat(curl->errorbuffer,": ");
strcat(curl->errorbuffer,str);
}
}
return err;
}
CURLcode
curl_global_init(long flags)
{
(void)flags;
2006-06-30 15:19:49 +02:00
return CURLE_OK;
}
void
curl_global_cleanup(void) {}
CURL *
curl_easy_init(void)
{
CURL *handle;
2008-04-21 21:13:36 +02:00
#ifdef HAVE_W32_SYSTEM
w32_init_sockets ();
#endif
2006-06-30 15:19:49 +02:00
handle=calloc(1,sizeof(CURL));
if(handle)
handle->errors=stderr;
return handle;
}
void
curl_easy_cleanup(CURL *curl)
{
if (curl)
{
2006-09-26 16:35:24 +02:00
http_close (curl->hd, 0);
free(curl);
}
2006-06-30 15:19:49 +02:00
}
CURLcode
curl_easy_setopt(CURL *curl,CURLoption option,...)
{
va_list ap;
va_start(ap,option);
switch(option)
{
case CURLOPT_URL:
curl->url=va_arg(ap,char *);
break;
case CURLOPT_USERPWD:
curl->auth=va_arg(ap,char *);
break;
case CURLOPT_WRITEFUNCTION:
curl->writer=va_arg(ap,write_func);
break;
case CURLOPT_FILE:
curl->file=va_arg(ap,void *);
break;
case CURLOPT_ERRORBUFFER:
curl->errorbuffer=va_arg(ap,char *);
break;
case CURLOPT_PROXY:
curl->proxy=va_arg(ap,char *);
break;
case CURLOPT_POST:
curl->flags.post=va_arg(ap,long)?1:0;
2006-06-30 15:19:49 +02:00
break;
case CURLOPT_POSTFIELDS:
curl->postfields=va_arg(ap,char *);
break;
case CURLOPT_SRVTAG_GPG_HACK:
curl->srvtag=va_arg(ap,char *);
break;
2006-06-30 15:19:49 +02:00
case CURLOPT_FAILONERROR:
curl->flags.failonerror=va_arg(ap,long)?1:0;
2006-06-30 15:19:49 +02:00
break;
case CURLOPT_VERBOSE:
curl->flags.verbose=va_arg(ap,long)?1:0;
2006-06-30 15:19:49 +02:00
break;
case CURLOPT_STDERR:
curl->errors=va_arg(ap,FILE *);
break;
case CURLOPT_HTTPHEADER:
curl->headers=va_arg(ap,struct curl_slist *);
break;
2006-06-30 15:19:49 +02:00
default:
/* We ignore the huge majority of curl options */
break;
}
return handle_error(curl,CURLE_OK,NULL);
}
CURLcode
curl_easy_perform(CURL *curl)
{
int rc;
CURLcode err=CURLE_OK;
const char *errstr=NULL;
char *proxy=NULL;
/* Emulate the libcurl proxy behavior. If the calling program set a
proxy, use it. If it didn't set a proxy or set it to NULL, check
for one in the environment. If the calling program explicitly
2006-07-27 16:18:55 +02:00
set a null-string proxy the http code doesn't use a proxy at
all. */
2006-06-30 15:19:49 +02:00
if(curl->proxy)
2006-07-27 16:18:55 +02:00
proxy=curl->proxy;
2006-06-30 15:19:49 +02:00
else
proxy=getenv(HTTP_PROXY_ENV);
if(curl->flags.verbose)
{
fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null");
fprintf(curl->errors,"* HTTP URL is \"%s\"\n",curl->url);
fprintf(curl->errors,"* HTTP auth is \"%s\"\n",
curl->auth?curl->auth:"null");
fprintf(curl->errors,"* HTTP method is %s\n",
curl->flags.post?"POST":"GET");
}
2006-06-30 15:19:49 +02:00
if(curl->flags.post)
{
rc = http_open (&curl->hd, HTTP_REQ_POST, curl->url, NULL, curl->auth,
0, proxy, NULL, curl->srvtag,
curl->headers?curl->headers->list:NULL);
if (!rc)
2006-06-30 15:19:49 +02:00
{
unsigned int post_len = strlen(curl->postfields);
es_fprintf (http_get_write_ptr (curl->hd),
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %u\r\n", post_len);
http_start_data (curl->hd);
es_write (http_get_write_ptr (curl->hd),
curl->postfields, post_len, NULL);
rc = http_wait_response (curl->hd);
curl->status = http_get_status_code (curl->hd);
if (!rc && curl->flags.failonerror && curl->status>=300)
err = CURLE_HTTP_RETURNED_ERROR;
2006-09-26 16:35:24 +02:00
http_close (curl->hd, 0);
curl->hd = NULL;
2006-06-30 15:19:49 +02:00
}
}
else
{
rc = http_open (&curl->hd, HTTP_REQ_GET, curl->url, NULL, curl->auth,
0, proxy, NULL, curl->srvtag,
curl->headers?curl->headers->list:NULL);
if (!rc)
2006-06-30 15:19:49 +02:00
{
rc = http_wait_response (curl->hd);
curl->status = http_get_status_code (curl->hd);
if (!rc)
2006-06-30 15:19:49 +02:00
{
if (curl->flags.failonerror && curl->status>=300)
err = CURLE_HTTP_RETURNED_ERROR;
2006-06-30 15:19:49 +02:00
else
{
size_t maxlen = 1024;
size_t buflen;
unsigned int len;
2006-09-26 16:35:24 +02:00
char *line = NULL;
2006-06-30 15:19:49 +02:00
while ((len = es_read_line (http_get_read_ptr (curl->hd),
&line, &buflen, &maxlen)))
2006-06-30 15:19:49 +02:00
{
size_t ret;
maxlen=1024;
ret=(curl->writer)(line,len,1,curl->file);
if(ret!=len)
{
err=CURLE_WRITE_ERROR;
break;
}
}
es_free (line);
2006-09-26 16:35:24 +02:00
http_close(curl->hd, 0);
curl->hd = NULL;
2006-06-30 15:19:49 +02:00
}
}
else
{
2006-09-26 16:35:24 +02:00
http_close (curl->hd, 0);
curl->hd = NULL;
}
2006-06-30 15:19:49 +02:00
}
}
2006-09-26 16:35:24 +02:00
switch(gpg_err_code (rc))
2006-06-30 15:19:49 +02:00
{
case 0:
break;
2006-09-26 16:35:24 +02:00
case GPG_ERR_INV_URI:
2006-06-30 15:19:49 +02:00
err=CURLE_UNSUPPORTED_PROTOCOL;
break;
default:
2006-09-26 16:35:24 +02:00
errstr=gpg_strerror (rc);
2006-06-30 15:19:49 +02:00
err=CURLE_COULDNT_CONNECT;
break;
}
2006-06-30 15:19:49 +02:00
return handle_error(curl,err,errstr);
}
/* This is not the same exact set that is allowed according to
RFC-2396, but it is what the real curl uses. */
#define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"0123456789"
char *
curl_escape(char *str,int length)
{
int len,max,idx,enc_idx=0;
char *enc;
if(length)
len=length;
else
len=strlen(str);
enc=malloc(len+1);
if(!enc)
return enc;
max=len;
for(idx=0;idx<len;idx++)
{
if(enc_idx+3>max)
{
char *tmp;
max+=100;
tmp=realloc(enc,max+1);
if(!tmp)
{
free(enc);
return NULL;
}
enc=tmp;
}
if(strchr(VALID_URI_CHARS,str[idx]))
enc[enc_idx++]=str[idx];
else
{
char numbuf[5];
sprintf(numbuf,"%%%02X",str[idx]);
strcpy(&enc[enc_idx],numbuf);
enc_idx+=3;
}
}
enc[enc_idx]='\0';
return enc;
}
curl_version_info_data *
curl_version_info(int type)
2006-06-30 15:19:49 +02:00
{
static curl_version_info_data data;
static const char *protocols[]={"http",NULL};
(void)type;
data.protocols=protocols;
return &data;
2006-06-30 15:19:49 +02:00
}
struct curl_slist *
curl_slist_append(struct curl_slist *list,const char *string)
{
if(!list)
{
list=calloc(1,sizeof(*list));
if(!list)
return NULL;
}
add_to_strlist(&list->list,string);
return list;
}
void
curl_slist_free_all(struct curl_slist *list)
{
if(list)
{
free_strlist(list->list);
free(list);
}
}