2006-12-21 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / keyserver / curl-shim.c
blob406e26ee0646d4b83e78cea3a8443e1ae163ab55
1 /* curl-shim.c - Implement a small subset of the curl API in terms of
2 * the iobuf HTTP API
4 * Copyright (C) 2005, 2006 Free Software Foundation, Inc.
6 * This file is part of GnuPG.
8 * GnuPG is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * GnuPG is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA.
24 #include <config.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <errno.h>
31 #include "http.h"
32 #include "util.h"
33 #include "ksutil.h"
34 #include "curl-shim.h"
36 static CURLcode
37 handle_error(CURL *curl,CURLcode err,const char *str)
39 if(curl->errorbuffer)
41 /* Make sure you never exceed CURL_ERROR_SIZE, currently set to
42 256 in curl-shim.h */
43 switch(err)
45 case CURLE_OK:
46 strcpy(curl->errorbuffer,"okay");
47 break;
49 case CURLE_UNSUPPORTED_PROTOCOL:
50 strcpy(curl->errorbuffer,"unsupported protocol");
51 break;
53 case CURLE_COULDNT_CONNECT:
54 strcpy(curl->errorbuffer,"couldn't connect");
55 break;
57 case CURLE_WRITE_ERROR:
58 strcpy(curl->errorbuffer,"write error");
59 break;
61 case CURLE_HTTP_RETURNED_ERROR:
62 sprintf(curl->errorbuffer,"url returned error %u",curl->status);
63 break;
65 default:
66 strcpy(curl->errorbuffer,"generic error");
67 break;
70 if(str && (strlen(curl->errorbuffer)+2+strlen(str)+1)<=CURL_ERROR_SIZE)
72 strcat(curl->errorbuffer,": ");
73 strcat(curl->errorbuffer,str);
77 return err;
80 CURLcode
81 curl_global_init(long flags)
83 return CURLE_OK;
86 void
87 curl_global_cleanup(void) {}
89 CURL *
90 curl_easy_init(void)
92 CURL *handle;
94 handle=calloc(1,sizeof(CURL));
95 if(handle)
96 handle->errors=stderr;
98 return handle;
101 void
102 curl_easy_cleanup(CURL *curl)
104 if (curl)
106 http_close (curl->hd, 0);
107 free(curl);
111 CURLcode
112 curl_easy_setopt(CURL *curl,CURLoption option,...)
114 va_list ap;
116 va_start(ap,option);
118 switch(option)
120 case CURLOPT_URL:
121 curl->url=va_arg(ap,char *);
122 break;
123 case CURLOPT_USERPWD:
124 curl->auth=va_arg(ap,char *);
125 break;
126 case CURLOPT_WRITEFUNCTION:
127 curl->writer=va_arg(ap,write_func);
128 break;
129 case CURLOPT_FILE:
130 curl->file=va_arg(ap,void *);
131 break;
132 case CURLOPT_ERRORBUFFER:
133 curl->errorbuffer=va_arg(ap,char *);
134 break;
135 case CURLOPT_PROXY:
136 curl->proxy=va_arg(ap,char *);
137 break;
138 case CURLOPT_POST:
139 curl->flags.post=va_arg(ap,unsigned int);
140 break;
141 case CURLOPT_POSTFIELDS:
142 curl->postfields=va_arg(ap,char *);
143 break;
144 case CURLOPT_FAILONERROR:
145 curl->flags.failonerror=va_arg(ap,unsigned int);
146 break;
147 case CURLOPT_VERBOSE:
148 curl->flags.verbose=va_arg(ap,unsigned int);
149 break;
150 case CURLOPT_STDERR:
151 curl->errors=va_arg(ap,FILE *);
152 break;
153 default:
154 /* We ignore the huge majority of curl options */
155 break;
158 return handle_error(curl,CURLE_OK,NULL);
161 CURLcode
162 curl_easy_perform(CURL *curl)
164 int rc;
165 CURLcode err=CURLE_OK;
166 const char *errstr=NULL;
167 char *proxy=NULL;
169 /* Emulate the libcurl proxy behavior. If the calling program set a
170 proxy, use it. If it didn't set a proxy or set it to NULL, check
171 for one in the environment. If the calling program explicitly
172 set a null-string proxy the http code doesn't use a proxy at
173 all. */
175 if(curl->proxy)
176 proxy=curl->proxy;
177 else
178 proxy=getenv(HTTP_PROXY_ENV);
180 if(curl->flags.verbose)
181 fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null");
183 if(curl->flags.post)
185 rc = http_open (&curl->hd, HTTP_REQ_POST, curl->url, curl->auth,
186 0, proxy, NULL);
187 if (!rc)
189 unsigned int post_len = strlen(curl->postfields);
191 es_fprintf (http_get_write_ptr (curl->hd),
192 "Content-Type: application/x-www-form-urlencoded\r\n"
193 "Content-Length: %u\r\n", post_len);
194 http_start_data (curl->hd);
195 es_write (http_get_write_ptr (curl->hd),
196 curl->postfields, post_len, NULL);
198 rc = http_wait_response (curl->hd);
199 curl->status = http_get_status_code (curl->hd);
200 if (!rc && curl->flags.failonerror && curl->status>=300)
201 err = CURLE_HTTP_RETURNED_ERROR;
202 http_close (curl->hd, 0);
203 curl->hd = NULL;
206 else
208 rc = http_open (&curl->hd, HTTP_REQ_GET, curl->url, curl->auth,
209 0, proxy, NULL);
210 if (!rc)
212 rc = http_wait_response (curl->hd);
213 curl->status = http_get_status_code (curl->hd);
214 if (!rc)
216 if (curl->flags.failonerror && curl->status>=300)
217 err = CURLE_HTTP_RETURNED_ERROR;
218 else
220 size_t maxlen = 1024;
221 size_t buflen;
222 unsigned int len;
223 char *line = NULL;
225 while ((len = es_read_line (http_get_read_ptr (curl->hd),
226 &line, &buflen, &maxlen)))
228 size_t ret;
230 maxlen=1024;
232 ret=(curl->writer)(line,len,1,curl->file);
233 if(ret!=len)
235 err=CURLE_WRITE_ERROR;
236 break;
240 es_free (line);
241 http_close(curl->hd, 0);
242 curl->hd = NULL;
245 else
247 http_close (curl->hd, 0);
248 curl->hd = NULL;
253 switch(gpg_err_code (rc))
255 case 0:
256 break;
258 case GPG_ERR_INV_URI:
259 err=CURLE_UNSUPPORTED_PROTOCOL;
260 break;
262 default:
263 errstr=gpg_strerror (rc);
264 err=CURLE_COULDNT_CONNECT;
265 break;
268 return handle_error(curl,err,errstr);
271 /* This is not the same exact set that is allowed according to
272 RFC-2396, but it is what the real curl uses. */
273 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \
274 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
275 "0123456789"
277 char *
278 curl_escape(char *str,int length)
280 int len,max,idx,enc_idx=0;
281 char *enc;
283 if(length)
284 len=length;
285 else
286 len=strlen(str);
288 enc=malloc(len+1);
289 if(!enc)
290 return enc;
292 max=len;
294 for(idx=0;idx<len;idx++)
296 if(enc_idx+3>max)
298 char *tmp;
300 max+=100;
302 tmp=realloc(enc,max+1);
303 if(!tmp)
305 free(enc);
306 return NULL;
309 enc=tmp;
312 if(strchr(VALID_URI_CHARS,str[idx]))
313 enc[enc_idx++]=str[idx];
314 else
316 char numbuf[5];
317 sprintf(numbuf,"%%%02X",str[idx]);
318 strcpy(&enc[enc_idx],numbuf);
319 enc_idx+=3;
323 enc[enc_idx]='\0';
325 return enc;
328 void
329 curl_free(char *ptr)
331 free(ptr);