1 /* curl-shim.c - Implement a small subset of the curl API in terms of
4 * Copyright (C) 2005, 2006, 2007, 2008, 2009 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 3 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, see <http://www.gnu.org/licenses/>.
32 #include "curl-shim.h"
35 handle_error(CURL
*curl
,CURLcode err
,const char *str
)
39 /* Make sure you never exceed CURL_ERROR_SIZE, currently set to
44 strcpy(curl
->errorbuffer
,"okay");
47 case CURLE_UNSUPPORTED_PROTOCOL
:
48 strcpy(curl
->errorbuffer
,"unsupported protocol");
51 case CURLE_COULDNT_CONNECT
:
52 strcpy(curl
->errorbuffer
,"couldn't connect");
55 case CURLE_WRITE_ERROR
:
56 strcpy(curl
->errorbuffer
,"write error");
59 case CURLE_HTTP_RETURNED_ERROR
:
60 sprintf(curl
->errorbuffer
,"url returned error %u",curl
->status
);
64 strcpy(curl
->errorbuffer
,"generic error");
68 if(str
&& (strlen(curl
->errorbuffer
)+2+strlen(str
)+1)<=CURL_ERROR_SIZE
)
70 strcat(curl
->errorbuffer
,": ");
71 strcat(curl
->errorbuffer
,str
);
79 curl_global_init(long flags
)
86 curl_global_cleanup(void) {}
93 #ifdef HAVE_W32_SYSTEM
97 handle
=calloc(1,sizeof(CURL
));
99 handle
->errors
=stderr
;
105 curl_easy_cleanup(CURL
*curl
)
109 http_close (curl
->hd
, 0);
115 curl_easy_setopt(CURL
*curl
,CURLoption option
,...)
124 curl
->url
=va_arg(ap
,char *);
126 case CURLOPT_USERPWD
:
127 curl
->auth
=va_arg(ap
,char *);
129 case CURLOPT_WRITEFUNCTION
:
130 curl
->writer
=va_arg(ap
,write_func
);
133 curl
->file
=va_arg(ap
,void *);
135 case CURLOPT_ERRORBUFFER
:
136 curl
->errorbuffer
=va_arg(ap
,char *);
139 curl
->proxy
=va_arg(ap
,char *);
142 curl
->flags
.post
=va_arg(ap
,long)?1:0;
144 case CURLOPT_POSTFIELDS
:
145 curl
->postfields
=va_arg(ap
,char *);
147 case CURLOPT_SRVTAG_GPG_HACK
:
148 curl
->srvtag
=va_arg(ap
,char *);
150 case CURLOPT_FAILONERROR
:
151 curl
->flags
.failonerror
=va_arg(ap
,long)?1:0;
153 case CURLOPT_VERBOSE
:
154 curl
->flags
.verbose
=va_arg(ap
,long)?1:0;
157 curl
->errors
=va_arg(ap
,FILE *);
159 case CURLOPT_HTTPHEADER
:
160 curl
->headers
=va_arg(ap
,struct curl_slist
*);
163 /* We ignore the huge majority of curl options */
167 return handle_error(curl
,CURLE_OK
,NULL
);
171 curl_easy_perform(CURL
*curl
)
174 CURLcode err
=CURLE_OK
;
175 const char *errstr
=NULL
;
178 /* Emulate the libcurl proxy behavior. If the calling program set a
179 proxy, use it. If it didn't set a proxy or set it to NULL, check
180 for one in the environment. If the calling program explicitly
181 set a null-string proxy the http code doesn't use a proxy at
187 proxy
=getenv(HTTP_PROXY_ENV
);
189 if(curl
->flags
.verbose
)
191 fprintf(curl
->errors
,"* HTTP proxy is \"%s\"\n",proxy
?proxy
:"null");
192 fprintf(curl
->errors
,"* HTTP URL is \"%s\"\n",curl
->url
);
193 fprintf(curl
->errors
,"* HTTP auth is \"%s\"\n",
194 curl
->auth
?curl
->auth
:"null");
195 fprintf(curl
->errors
,"* HTTP method is %s\n",
196 curl
->flags
.post
?"POST":"GET");
201 rc
= http_open (&curl
->hd
, HTTP_REQ_POST
, curl
->url
, curl
->auth
,
202 0, proxy
, NULL
, curl
->srvtag
,
203 curl
->headers
?curl
->headers
->list
:NULL
);
206 unsigned int post_len
= strlen(curl
->postfields
);
208 es_fprintf (http_get_write_ptr (curl
->hd
),
209 "Content-Type: application/x-www-form-urlencoded\r\n"
210 "Content-Length: %u\r\n", post_len
);
211 http_start_data (curl
->hd
);
212 es_write (http_get_write_ptr (curl
->hd
),
213 curl
->postfields
, post_len
, NULL
);
215 rc
= http_wait_response (curl
->hd
);
216 curl
->status
= http_get_status_code (curl
->hd
);
217 if (!rc
&& curl
->flags
.failonerror
&& curl
->status
>=300)
218 err
= CURLE_HTTP_RETURNED_ERROR
;
219 http_close (curl
->hd
, 0);
225 rc
= http_open (&curl
->hd
, HTTP_REQ_GET
, curl
->url
, curl
->auth
,
226 0, proxy
, NULL
, curl
->srvtag
,
227 curl
->headers
?curl
->headers
->list
:NULL
);
230 rc
= http_wait_response (curl
->hd
);
231 curl
->status
= http_get_status_code (curl
->hd
);
234 if (curl
->flags
.failonerror
&& curl
->status
>=300)
235 err
= CURLE_HTTP_RETURNED_ERROR
;
238 size_t maxlen
= 1024;
243 while ((len
= es_read_line (http_get_read_ptr (curl
->hd
),
244 &line
, &buflen
, &maxlen
)))
250 ret
=(curl
->writer
)(line
,len
,1,curl
->file
);
253 err
=CURLE_WRITE_ERROR
;
259 http_close(curl
->hd
, 0);
265 http_close (curl
->hd
, 0);
271 switch(gpg_err_code (rc
))
276 case GPG_ERR_INV_URI
:
277 err
=CURLE_UNSUPPORTED_PROTOCOL
;
281 errstr
=gpg_strerror (rc
);
282 err
=CURLE_COULDNT_CONNECT
;
286 return handle_error(curl
,err
,errstr
);
289 /* This is not the same exact set that is allowed according to
290 RFC-2396, but it is what the real curl uses. */
291 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \
292 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
296 curl_escape(char *str
,int length
)
298 int len
,max
,idx
,enc_idx
=0;
312 for(idx
=0;idx
<len
;idx
++)
320 tmp
=realloc(enc
,max
+1);
330 if(strchr(VALID_URI_CHARS
,str
[idx
]))
331 enc
[enc_idx
++]=str
[idx
];
335 sprintf(numbuf
,"%%%02X",str
[idx
]);
336 strcpy(&enc
[enc_idx
],numbuf
);
346 curl_version_info_data
*
347 curl_version_info(int type
)
349 static curl_version_info_data data
;
350 static const char *protocols
[]={"http",NULL
};
354 data
.protocols
=protocols
;
360 curl_slist_append(struct curl_slist
*list
,const char *string
)
364 list
=calloc(1,sizeof(*list
));
369 add_to_strlist(&list
->list
,string
);
375 curl_slist_free_all(struct curl_slist
*list
)
379 free_strlist(list
->list
);