Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * pkix_pl_httpdefaultclient.c | |
6 * | |
7 * HTTPDefaultClient Function Definitions | |
8 * | |
9 */ | |
10 | |
11 #include "pkix_pl_httpdefaultclient.h" | |
12 | |
13 static void *plContext = NULL; | |
14 | |
15 /* | |
16 * The interface specification for an http client requires that it register | |
17 * a function table of type SEC_HttpClientFcn, which is defined as a union | |
18 * of tables, of which only version 1 is defined at present. | |
19 * | |
20 * Note: these functions violate the PKIX calling conventions, in that they | |
21 * return SECStatus rather than PKIX_Error*, and that they do not provide a | |
22 * plContext argument. They are implemented here as calls to PKIX functions, | |
23 * but the plContext value is circularly defined - a true kludge. Its value | |
24 * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for | |
25 * subsequent use, but since that initial call comes from the | |
26 * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved. | |
27 */ | |
28 static SEC_HttpClientFcnV1 vtable = { | |
29 pkix_pl_HttpDefaultClient_CreateSessionFcn, | |
30 pkix_pl_HttpDefaultClient_KeepAliveSessionFcn, | |
31 pkix_pl_HttpDefaultClient_FreeSessionFcn, | |
32 pkix_pl_HttpDefaultClient_RequestCreateFcn, | |
33 pkix_pl_HttpDefaultClient_SetPostDataFcn, | |
34 pkix_pl_HttpDefaultClient_AddHeaderFcn, | |
35 pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn, | |
36 pkix_pl_HttpDefaultClient_CancelFcn, | |
37 pkix_pl_HttpDefaultClient_FreeFcn | |
38 }; | |
39 | |
40 static SEC_HttpClientFcn httpClient; | |
41 | |
42 static const char *eohMarker = "\r\n\r\n"; | |
43 static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */ | |
44 static const char *crlf = "\r\n"; | |
45 static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */ | |
46 static const char *httpprotocol = "HTTP/"; | |
47 static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */ | |
48 | |
49 | |
50 #define HTTP_UNKNOWN_CONTENT_LENGTH -1 | |
51 | |
52 /* --Private-HttpDefaultClient-Functions------------------------- */ | |
53 | |
54 /* | |
55 * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete | |
56 * DESCRIPTION: | |
57 * | |
58 * This function determines whether the headers in the current receive buffer | |
59 * in the HttpDefaultClient pointed to by "client" are complete. If so, the | |
60 * input data is checked for status code, content-type and content-length are | |
61 * extracted, and the client is set up to read the body of the response. | |
62 * Otherwise, the client is set up to continue reading header data. | |
63 * | |
64 * PARAMETERS: | |
65 * "client" | |
66 * The address of the HttpDefaultClient object. Must be non-NULL. | |
67 * "bytesRead" | |
68 * The UInt32 number of bytes received in the latest read. | |
69 * "pKeepGoing" | |
70 * The address at which the Boolean state machine flag is stored to | |
71 * indicate whether processing can continue without further input. | |
72 * Must be non-NULL. | |
73 * "plContext" | |
74 * Platform-specific context pointer. | |
75 * THREAD SAFETY: | |
76 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
77 * RETURNS: | |
78 * Returns NULL if the function succeeds. | |
79 * Returns a HttpDefaultClient Error if the function fails in a | |
80 * non-fatal way. | |
81 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
82 */ | |
83 static PKIX_Error * | |
84 pkix_pl_HttpDefaultClient_HdrCheckComplete( | |
85 PKIX_PL_HttpDefaultClient *client, | |
86 PKIX_UInt32 bytesRead, | |
87 PKIX_Boolean *pKeepGoing, | |
88 void *plContext) | |
89 { | |
90 PKIX_UInt32 alreadyScanned = 0; | |
91 PKIX_UInt32 comp = 0; | |
92 PKIX_UInt32 headerLength = 0; | |
93 PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH; | |
94 char *eoh = NULL; | |
95 char *statusLineEnd = NULL; | |
96 char *space = NULL; | |
97 char *nextHeader = NULL; | |
98 const char *httpcode = NULL; | |
99 char *thisHeaderEnd = NULL; | |
100 char *value = NULL; | |
101 char *colon = NULL; | |
102 char *copy = NULL; | |
103 char *body = NULL; | |
104 | |
105 PKIX_ENTER | |
106 (HTTPDEFAULTCLIENT, | |
107 "pkix_pl_HttpDefaultClient_HdrCheckComplete"); | |
108 PKIX_NULLCHECK_TWO(client, pKeepGoing); | |
109 | |
110 *pKeepGoing = PKIX_FALSE; | |
111 | |
112 /* Does buffer contain end-of-header marker? */ | |
113 | |
114 /* Copy number of scanned bytes into a variable. */ | |
115 alreadyScanned = client->filledupBytes; | |
116 /* | |
117 * If this is the initial buffer, we have to scan from the beginning. | |
118 * If we scanned, failed to find eohMarker, and read some more, we | |
119 * only have to scan from where we left off. | |
120 */ | |
121 if (alreadyScanned > eohMarkLen) { | |
122 /* Back up and restart scanning over a few bytes that were | |
123 * scanned before */ | |
124 PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen; | |
125 eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker, | |
126 bytesRead + searchStartPos); | |
127 } else { | |
128 /* A search from the beginning of the buffer. */ | |
129 eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead); | |
130 } | |
131 | |
132 client->filledupBytes += bytesRead; | |
133 | |
134 if (eoh == NULL) { /* did we see end-of-header? */ | |
135 /* No. Continue to read header data */ | |
136 client->connectStatus = HTTP_RECV_HDR; | |
137 *pKeepGoing = PKIX_TRUE; | |
138 goto cleanup; | |
139 } | |
140 | |
141 /* Yes. Calculate how many bytes in header (not counting eohMarker) */ | |
142 headerLength = (eoh - client->rcvBuf); | |
143 | |
144 /* allocate space to copy header (and for the NULL terminator) */ | |
145 PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)©, plContext), | |
146 PKIX_MALLOCFAILED); | |
147 | |
148 /* copy header data before we corrupt it (by storing NULLs) */ | |
149 PORT_Memcpy(copy, client->rcvBuf, headerLength); | |
150 /* Store the NULL terminator */ | |
151 copy[headerLength] = '\0'; | |
152 client->rcvHeaders = copy; | |
153 | |
154 /* Did caller want a pointer to header? */ | |
155 if (client->rcv_http_headers != NULL) { | |
156 /* store pointer for caller */ | |
157 *(client->rcv_http_headers) = copy; | |
158 } | |
159 | |
160 /* Check that message status is okay. */ | |
161 statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity); | |
162 if (statusLineEnd == NULL) { | |
163 client->connectStatus = HTTP_ERROR; | |
164 PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); | |
165 goto cleanup; | |
166 } | |
167 | |
168 *statusLineEnd = '\0'; | |
169 | |
170 space = strchr((const char *)client->rcvBuf, ' '); | |
171 if (space == NULL) { | |
172 client->connectStatus = HTTP_ERROR; | |
173 goto cleanup; | |
174 } | |
175 | |
176 comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol, | |
177 httpprotocolLen); | |
178 if (comp != 0) { | |
179 client->connectStatus = HTTP_ERROR; | |
180 goto cleanup; | |
181 } | |
182 | |
183 httpcode = space + 1; | |
184 space = strchr(httpcode, ' '); | |
185 if (space == NULL) { | |
186 client->connectStatus = HTTP_ERROR; | |
187 goto cleanup; | |
188 } | |
189 *space = '\0'; | |
190 | |
191 client->responseCode = atoi(httpcode); | |
192 if (client->responseCode != 200) { | |
193 client->connectStatus = HTTP_ERROR; | |
194 goto cleanup; | |
195 } | |
196 | |
197 /* Find the content-type and content-length */ | |
198 nextHeader = statusLineEnd + crlfLen; | |
199 *eoh = '\0'; | |
200 do { | |
201 thisHeaderEnd = NULL; | |
202 value = NULL; | |
203 | |
204 colon = strchr(nextHeader, ':'); | |
205 if (colon == NULL) { | |
206 client->connectStatus = HTTP_ERROR; | |
207 goto cleanup; | |
208 } | |
209 *colon = '\0'; | |
210 value = colon + 1; | |
211 if (*value != ' ') { | |
212 client->connectStatus = HTTP_ERROR; | |
213 goto cleanup; | |
214 } | |
215 value++; | |
216 thisHeaderEnd = strstr(value, crlf); | |
217 if (thisHeaderEnd != NULL) { | |
218 *thisHeaderEnd = '\0'; | |
219 } | |
220 comp = PORT_Strcasecmp(nextHeader, "content-type"); | |
221 if (comp == 0) { | |
222 client->rcvContentType = PORT_Strdup(value); | |
223 } else { | |
224 comp = PORT_Strcasecmp(nextHeader, "content-length"); | |
225 if (comp == 0) { | |
226 contentLength = atoi(value); | |
227 } | |
228 } | |
229 if (thisHeaderEnd != NULL) { | |
230 nextHeader = thisHeaderEnd + crlfLen; | |
231 } else { | |
232 nextHeader = NULL; | |
233 } | |
234 } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen))); | |
235 | |
236 /* Did caller provide a pointer to return content-type? */ | |
237 if (client->rcv_http_content_type != NULL) { | |
238 *(client->rcv_http_content_type) = client->rcvContentType; | |
239 } | |
240 | |
241 if (client->rcvContentType == NULL) { | |
242 client->connectStatus = HTTP_ERROR; | |
243 goto cleanup; | |
244 } | |
245 | |
246 /* How many bytes remain in current buffer, beyond the header? */ | |
247 headerLength += eohMarkLen; | |
248 client->filledupBytes -= headerLength; | |
249 | |
250 /* | |
251 * The headers have passed validation. Now figure out whether the | |
252 * message is within the caller's size limit (if one was specified). | |
253 */ | |
254 switch (contentLength) { | |
255 case 0: | |
256 client->rcv_http_data_len = 0; | |
257 client->connectStatus = HTTP_COMPLETE; | |
258 *pKeepGoing = PKIX_FALSE; | |
259 break; | |
260 | |
261 case HTTP_UNKNOWN_CONTENT_LENGTH: | |
262 /* Unknown contentLength indicator.Will be set by | |
263 * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */ | |
264 client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH; | |
265 contentLength = /* Try to reserve 4K+ buffer */ | |
266 client->filledupBytes + HTTP_DATA_BUFSIZE; | |
267 if (client->maxResponseLen > 0 && | |
268 contentLength > client->maxResponseLen) { | |
269 if (client->filledupBytes < client->maxResponseLen) { | |
270 contentLength = client->maxResponseLen; | |
271 } else { | |
272 client->connectStatus = HTTP_ERROR; | |
273 goto cleanup; | |
274 } | |
275 } | |
276 /* set available number of bytes in the buffer */ | |
277 client->capacity = contentLength; | |
278 client->connectStatus = HTTP_RECV_BODY; | |
279 *pKeepGoing = PKIX_TRUE; | |
280 break; | |
281 | |
282 default: | |
283 client->rcv_http_data_len = contentLength; | |
284 if (client->maxResponseLen > 0 && | |
285 client->maxResponseLen < contentLength) { | |
286 client->connectStatus = HTTP_ERROR; | |
287 goto cleanup; | |
288 } | |
289 | |
290 /* | |
291 * Do we have all of the message body, or do we need to read some more? | |
292 */ | |
293 if (client->filledupBytes < contentLength) { | |
294 client->connectStatus = HTTP_RECV_BODY; | |
295 *pKeepGoing = PKIX_TRUE; | |
296 } else { | |
297 client->connectStatus = HTTP_COMPLETE; | |
298 *pKeepGoing = PKIX_FALSE; | |
299 } | |
300 } | |
301 | |
302 if (contentLength > 0) { | |
303 /* allocate a buffer of size contentLength for the content */ | |
304 PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plContext), | |
305 PKIX_MALLOCFAILED); | |
306 | |
307 /* copy any remaining bytes in current buffer into new buffer */ | |
308 if (client->filledupBytes > 0) { | |
309 PORT_Memcpy(body, &(client->rcvBuf[headerLength]), | |
310 client->filledupBytes); | |
311 } | |
312 } | |
313 | |
314 PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plContext), | |
315 PKIX_FREEFAILED); | |
316 client->rcvBuf = body; | |
317 | |
318 cleanup: | |
319 | |
320 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
321 } | |
322 | |
323 /* | |
324 * FUNCTION: PKIX_PL_HttpDefaultClient_Create | |
325 * DESCRIPTION: | |
326 * | |
327 * This function creates a new HttpDefaultClient, and stores the result at | |
328 * "pClient". | |
329 * | |
330 * The HttpClient API does not include a plContext argument in its | |
331 * function calls. Its value at the time of this Create call must be the | |
332 * same as when the client is invoked. | |
333 * | |
334 * PARAMETERS: | |
335 * "host" | |
336 * The name of the server with which we hope to exchange messages. Must | |
337 * be non-NULL. | |
338 * "portnum" | |
339 * The port number to be used for our connection to the server. | |
340 * "pClient" | |
341 * The address at which the created HttpDefaultClient is to be stored. | |
342 * Must be non-NULL. | |
343 * "plContext" | |
344 * Platform-specific context pointer. | |
345 * THREAD SAFETY: | |
346 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
347 * RETURNS: | |
348 * Returns NULL if the function succeeds. | |
349 * Returns a HttpDefaultClient Error if the function fails in | |
350 * a non-fatal way. | |
351 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
352 */ | |
353 static PKIX_Error * | |
354 pkix_pl_HttpDefaultClient_Create( | |
355 const char *host, | |
356 PRUint16 portnum, | |
357 PKIX_PL_HttpDefaultClient **pClient, | |
358 void *plContext) | |
359 { | |
360 PKIX_PL_HttpDefaultClient *client = NULL; | |
361 | |
362 PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create"); | |
363 PKIX_NULLCHECK_TWO(pClient, host); | |
364 | |
365 /* allocate an HttpDefaultClient */ | |
366 PKIX_CHECK(PKIX_PL_Object_Alloc | |
367 (PKIX_HTTPDEFAULTCLIENT_TYPE, | |
368 sizeof (PKIX_PL_HttpDefaultClient), | |
369 (PKIX_PL_Object **)&client, | |
370 plContext), | |
371 PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT); | |
372 | |
373 /* Client timeout is overwritten in HttpDefaultClient_RequestCreate | |
374 * function. Default value will be ignored. */ | |
375 client->timeout = 0; | |
376 client->connectStatus = HTTP_NOT_CONNECTED; | |
377 client->portnum = portnum; | |
378 client->bytesToWrite = 0; | |
379 client->send_http_data_len = 0; | |
380 client->rcv_http_data_len = 0; | |
381 client->capacity = 0; | |
382 client->filledupBytes = 0; | |
383 client->responseCode = 0; | |
384 client->maxResponseLen = 0; | |
385 client->GETLen = 0; | |
386 client->POSTLen = 0; | |
387 client->pRcv_http_data_len = NULL; | |
388 client->callbackList = NULL; | |
389 client->GETBuf = NULL; | |
390 client->POSTBuf = NULL; | |
391 client->rcvBuf = NULL; | |
392 /* "host" is a parsing result by CERT_GetURL function that adds | |
393 * "end of line" to the value. OK to dup the string. */ | |
394 client->host = PORT_Strdup(host); | |
395 if (!client->host) { | |
396 PKIX_ERROR(PKIX_ALLOCERROR); | |
397 } | |
398 client->path = NULL; | |
399 client->rcvContentType = NULL; | |
400 client->rcvHeaders = NULL; | |
401 client->send_http_method = HTTP_POST_METHOD; | |
402 client->send_http_content_type = NULL; | |
403 client->send_http_data = NULL; | |
404 client->rcv_http_response_code = NULL; | |
405 client->rcv_http_content_type = NULL; | |
406 client->rcv_http_headers = NULL; | |
407 client->rcv_http_data = NULL; | |
408 client->socket = NULL; | |
409 | |
410 /* | |
411 * The HttpClient API does not include a plContext argument in its | |
412 * function calls. Save it here. | |
413 */ | |
414 client->plContext = plContext; | |
415 | |
416 *pClient = client; | |
417 | |
418 cleanup: | |
419 if (PKIX_ERROR_RECEIVED) { | |
420 PKIX_DECREF(client); | |
421 } | |
422 | |
423 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
424 } | |
425 | |
426 /* | |
427 * FUNCTION: pkix_pl_HttpDefaultClient_Destroy | |
428 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) | |
429 */ | |
430 static PKIX_Error * | |
431 pkix_pl_HttpDefaultClient_Destroy( | |
432 PKIX_PL_Object *object, | |
433 void *plContext) | |
434 { | |
435 PKIX_PL_HttpDefaultClient *client = NULL; | |
436 | |
437 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy"); | |
438 PKIX_NULLCHECK_ONE(object); | |
439 | |
440 PKIX_CHECK(pkix_CheckType | |
441 (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plContext), | |
442 PKIX_OBJECTNOTANHTTPDEFAULTCLIENT); | |
443 | |
444 client = (PKIX_PL_HttpDefaultClient *)object; | |
445 | |
446 if (client->rcvHeaders) { | |
447 PKIX_PL_Free(client->rcvHeaders, plContext); | |
448 client->rcvHeaders = NULL; | |
449 } | |
450 if (client->rcvContentType) { | |
451 PORT_Free(client->rcvContentType); | |
452 client->rcvContentType = NULL; | |
453 } | |
454 if (client->GETBuf != NULL) { | |
455 PR_smprintf_free(client->GETBuf); | |
456 client->GETBuf = NULL; | |
457 } | |
458 if (client->POSTBuf != NULL) { | |
459 PKIX_PL_Free(client->POSTBuf, plContext); | |
460 client->POSTBuf = NULL; | |
461 } | |
462 if (client->rcvBuf != NULL) { | |
463 PKIX_PL_Free(client->rcvBuf, plContext); | |
464 client->rcvBuf = NULL; | |
465 } | |
466 if (client->host) { | |
467 PORT_Free(client->host); | |
468 client->host = NULL; | |
469 } | |
470 if (client->path) { | |
471 PORT_Free(client->path); | |
472 client->path = NULL; | |
473 } | |
474 PKIX_DECREF(client->socket); | |
475 | |
476 cleanup: | |
477 | |
478 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
479 } | |
480 | |
481 /* | |
482 * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf | |
483 * | |
484 * DESCRIPTION: | |
485 * Registers PKIX_PL_HTTPDEFAULTCLIENT_TYPE and its related | |
486 * functions with systemClasses[] | |
487 * | |
488 * THREAD SAFETY: | |
489 * Not Thread Safe - for performance and complexity reasons | |
490 * | |
491 * Since this function is only called by PKIX_PL_Initialize, which should | |
492 * only be called once, it is acceptable that this function is not | |
493 * thread-safe. | |
494 */ | |
495 PKIX_Error * | |
496 pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext) | |
497 { | |
498 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; | |
499 pkix_ClassTable_Entry *entry = | |
500 &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE]; | |
501 | |
502 PKIX_ENTER(HTTPDEFAULTCLIENT, | |
503 "pkix_pl_HttpDefaultClient_RegisterSelf"); | |
504 | |
505 entry->description = "HttpDefaultClient"; | |
506 entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient); | |
507 entry->destructor = pkix_pl_HttpDefaultClient_Destroy; | |
508 | |
509 httpClient.version = 1; | |
510 httpClient.fcnTable.ftable1 = vtable; | |
511 (void)SEC_RegisterDefaultHttpClient(&httpClient); | |
512 | |
513 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
514 } | |
515 | |
516 /* --Private-HttpDefaultClient-I/O-Functions---------------------------- */ | |
517 /* | |
518 * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue | |
519 * DESCRIPTION: | |
520 * | |
521 * This function determines whether a socket Connect initiated earlier for the | |
522 * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag | |
523 * indicating whether processing can continue without further input. | |
524 * | |
525 * PARAMETERS: | |
526 * "client" | |
527 * The address of the HttpDefaultClient object. Must be non-NULL. | |
528 * "pKeepGoing" | |
529 * The address at which the Boolean state machine flag is stored to | |
530 * indicate whether processing can continue without further input. | |
531 * Must be non-NULL. | |
532 * "plContext" | |
533 * Platform-specific context pointer. | |
534 * THREAD SAFETY: | |
535 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
536 * RETURNS: | |
537 * Returns NULL if the function succeeds. | |
538 * Returns a HttpDefaultClient Error if the function fails in a | |
539 * non-fatal way. | |
540 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
541 */ | |
542 static PKIX_Error * | |
543 pkix_pl_HttpDefaultClient_ConnectContinue( | |
544 PKIX_PL_HttpDefaultClient *client, | |
545 PKIX_Boolean *pKeepGoing, | |
546 void *plContext) | |
547 { | |
548 PRErrorCode status; | |
549 PKIX_Boolean keepGoing = PKIX_FALSE; | |
550 PKIX_PL_Socket_Callback *callbackList = NULL; | |
551 | |
552 PKIX_ENTER | |
553 (HTTPDEFAULTCLIENT, | |
554 "pkix_pl_HttpDefaultClient_ConnectContinue"); | |
555 PKIX_NULLCHECK_ONE(client); | |
556 | |
557 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
558 | |
559 PKIX_CHECK(callbackList->connectcontinueCallback | |
560 (client->socket, &status, plContext), | |
561 PKIX_SOCKETCONNECTCONTINUEFAILED); | |
562 | |
563 if (status == 0) { | |
564 client->connectStatus = HTTP_CONNECTED; | |
565 keepGoing = PKIX_TRUE; | |
566 } else if (status != PR_IN_PROGRESS_ERROR) { | |
567 PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION); | |
568 } | |
569 | |
570 *pKeepGoing = keepGoing; | |
571 | |
572 cleanup: | |
573 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
574 } | |
575 | |
576 /* | |
577 * FUNCTION: pkix_pl_HttpDefaultClient_Send | |
578 * DESCRIPTION: | |
579 * | |
580 * This function creates and sends HTTP-protocol headers and, if applicable, | |
581 * data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag | |
582 * indicating whether processing can continue without further input, and at | |
583 * "pBytesTransferred" the number of bytes sent. | |
584 * | |
585 * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use | |
586 * and that transmission has not completed. | |
587 * | |
588 * PARAMETERS: | |
589 * "client" | |
590 * The address of the HttpDefaultClient object. Must be non-NULL. | |
591 * "pKeepGoing" | |
592 * The address at which the Boolean state machine flag is stored to | |
593 * indicate whether processing can continue without further input. | |
594 * Must be non-NULL. | |
595 * "pBytesTransferred" | |
596 * The address at which the number of bytes sent is stored. Must be | |
597 * non-NULL. | |
598 * "plContext" | |
599 * Platform-specific context pointer. | |
600 * THREAD SAFETY: | |
601 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
602 * RETURNS: | |
603 * Returns NULL if the function succeeds. | |
604 * Returns a HttpDefaultClient Error if the function fails in a | |
605 * non-fatal way. | |
606 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
607 */ | |
608 static PKIX_Error * | |
609 pkix_pl_HttpDefaultClient_Send( | |
610 PKIX_PL_HttpDefaultClient *client, | |
611 PKIX_Boolean *pKeepGoing, | |
612 PKIX_UInt32 *pBytesTransferred, | |
613 void *plContext) | |
614 { | |
615 PKIX_Int32 bytesWritten = 0; | |
616 PKIX_Int32 lenToWrite = 0; | |
617 PKIX_PL_Socket_Callback *callbackList = NULL; | |
618 char *dataToWrite = NULL; | |
619 | |
620 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send"); | |
621 PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); | |
622 | |
623 *pKeepGoing = PKIX_FALSE; | |
624 | |
625 /* Do we have anything waiting to go? */ | |
626 if ((client->GETBuf) || (client->POSTBuf)) { | |
627 | |
628 if (client->GETBuf) { | |
629 dataToWrite = client->GETBuf; | |
630 lenToWrite = client->GETLen; | |
631 } else { | |
632 dataToWrite = client->POSTBuf; | |
633 lenToWrite = client->POSTLen; | |
634 } | |
635 | |
636 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
637 | |
638 PKIX_CHECK(callbackList->sendCallback | |
639 (client->socket, | |
640 dataToWrite, | |
641 lenToWrite, | |
642 &bytesWritten, | |
643 plContext), | |
644 PKIX_SOCKETSENDFAILED); | |
645 | |
646 client->rcvBuf = NULL; | |
647 client->capacity = 0; | |
648 client->filledupBytes = 0; | |
649 | |
650 /* | |
651 * If the send completed we can proceed to try for the | |
652 * response. If the send did not complete we will have | |
653 * to poll for completion later. | |
654 */ | |
655 if (bytesWritten >= 0) { | |
656 client->connectStatus = HTTP_RECV_HDR; | |
657 *pKeepGoing = PKIX_TRUE; | |
658 } else { | |
659 client->connectStatus = HTTP_SEND_PENDING; | |
660 *pKeepGoing = PKIX_FALSE; | |
661 } | |
662 | |
663 } | |
664 | |
665 *pBytesTransferred = bytesWritten; | |
666 | |
667 cleanup: | |
668 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
669 } | |
670 | |
671 /* | |
672 * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue | |
673 * DESCRIPTION: | |
674 * | |
675 * This function determines whether the sending of the HTTP message for the | |
676 * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a | |
677 * flag indicating whether processing can continue without further input, and | |
678 * at "pBytesTransferred" the number of bytes sent. | |
679 * | |
680 * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use | |
681 * and that transmission has not completed. | |
682 * | |
683 * PARAMETERS: | |
684 * "client" | |
685 * The address of the HttpDefaultClient object. Must be non-NULL. | |
686 * "pKeepGoing" | |
687 * The address at which the Boolean state machine flag is stored to | |
688 * indicate whether processing can continue without further input. | |
689 * Must be non-NULL. | |
690 * "pBytesTransferred" | |
691 * The address at which the number of bytes sent is stored. Must be | |
692 * non-NULL. | |
693 * "plContext" | |
694 * Platform-specific context pointer. | |
695 * THREAD SAFETY: | |
696 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
697 * RETURNS: | |
698 * Returns NULL if the function succeeds. | |
699 * Returns a HttpDefaultClient Error if the function fails in a | |
700 * non-fatal way. | |
701 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
702 */ | |
703 static PKIX_Error * | |
704 pkix_pl_HttpDefaultClient_SendContinue( | |
705 PKIX_PL_HttpDefaultClient *client, | |
706 PKIX_Boolean *pKeepGoing, | |
707 PKIX_UInt32 *pBytesTransferred, | |
708 void *plContext) | |
709 { | |
710 PKIX_Int32 bytesWritten = 0; | |
711 PKIX_PL_Socket_Callback *callbackList = NULL; | |
712 | |
713 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue"); | |
714 PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); | |
715 | |
716 *pKeepGoing = PKIX_FALSE; | |
717 | |
718 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
719 | |
720 PKIX_CHECK(callbackList->pollCallback | |
721 (client->socket, &bytesWritten, NULL, plContext), | |
722 PKIX_SOCKETPOLLFAILED); | |
723 | |
724 /* | |
725 * If the send completed we can proceed to try for the | |
726 * response. If the send did not complete we will have | |
727 * continue to poll. | |
728 */ | |
729 if (bytesWritten >= 0) { | |
730 client->connectStatus = HTTP_RECV_HDR; | |
731 *pKeepGoing = PKIX_TRUE; | |
732 } | |
733 | |
734 *pBytesTransferred = bytesWritten; | |
735 | |
736 cleanup: | |
737 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
738 } | |
739 | |
740 /* | |
741 * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr | |
742 * DESCRIPTION: | |
743 * | |
744 * This function receives HTTP headers for the HttpDefaultClient "client", and | |
745 * stores in "pKeepGoing" a flag indicating whether processing can continue | |
746 * without further input. | |
747 * | |
748 * PARAMETERS: | |
749 * "client" | |
750 * The address of the HttpDefaultClient object. Must be non-NULL. | |
751 * "pKeepGoing" | |
752 * The address at which the Boolean state machine flag is stored to | |
753 * indicate whether processing can continue without further input. | |
754 * Must be non-NULL. | |
755 * "plContext" | |
756 * Platform-specific context pointer. | |
757 * THREAD SAFETY: | |
758 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
759 * RETURNS: | |
760 * Returns NULL if the function succeeds. | |
761 * Returns a HttpDefaultClient Error if the function fails in a | |
762 * non-fatal way. | |
763 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
764 */ | |
765 static PKIX_Error * | |
766 pkix_pl_HttpDefaultClient_RecvHdr( | |
767 PKIX_PL_HttpDefaultClient *client, | |
768 PKIX_Boolean *pKeepGoing, | |
769 void *plContext) | |
770 { | |
771 PKIX_UInt32 bytesToRead = 0; | |
772 PKIX_Int32 bytesRead = 0; | |
773 PKIX_PL_Socket_Callback *callbackList = NULL; | |
774 | |
775 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr"); | |
776 PKIX_NULLCHECK_TWO(client, pKeepGoing); | |
777 | |
778 /* | |
779 * rcvbuf, capacity, and filledupBytes were | |
780 * initialized when we wrote the headers. We begin by reading | |
781 * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and | |
782 * reading again if necessary, until we have read the end-of-header | |
783 * marker, "\r\n\r\n", or have reached our maximum. | |
784 */ | |
785 client->capacity += HTTP_HEADER_BUFSIZE; | |
786 PKIX_CHECK(PKIX_PL_Realloc | |
787 (client->rcvBuf, | |
788 client->capacity, | |
789 (void **)&(client->rcvBuf), | |
790 plContext), | |
791 PKIX_REALLOCFAILED); | |
792 | |
793 bytesToRead = client->capacity - client->filledupBytes; | |
794 | |
795 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
796 | |
797 PKIX_CHECK(callbackList->recvCallback | |
798 (client->socket, | |
799 (void *)&(client->rcvBuf[client->filledupBytes]), | |
800 bytesToRead, | |
801 &bytesRead, | |
802 plContext), | |
803 PKIX_SOCKETRECVFAILED); | |
804 | |
805 if (bytesRead > 0) { | |
806 /* client->filledupBytes will be adjusted by | |
807 * pkix_pl_HttpDefaultClient_HdrCheckComplete */ | |
808 PKIX_CHECK( | |
809 pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead, | |
810 pKeepGoing, | |
811 plContext), | |
812 PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED); | |
813 } else { | |
814 client->connectStatus = HTTP_RECV_HDR_PENDING; | |
815 *pKeepGoing = PKIX_FALSE; | |
816 } | |
817 | |
818 cleanup: | |
819 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
820 } | |
821 | |
822 /* | |
823 * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue | |
824 * DESCRIPTION: | |
825 * | |
826 * This function determines whether the receiving of the HTTP headers for the | |
827 * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag | |
828 * indicating whether processing can continue without further input. | |
829 * | |
830 * PARAMETERS: | |
831 * "client" | |
832 * The address of the HttpDefaultClient object. Must be non-NULL. | |
833 * "pKeepGoing" | |
834 * The address at which the Boolean state machine flag is stored to | |
835 * indicate whether processing can continue without further input. | |
836 * Must be non-NULL. | |
837 * "plContext" | |
838 * Platform-specific context pointer. | |
839 * THREAD SAFETY: | |
840 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
841 * RETURNS: | |
842 * Returns NULL if the function succeeds. | |
843 * Returns a HttpDefaultClient Error if the function fails in a | |
844 * non-fatal way. | |
845 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
846 */ | |
847 static PKIX_Error * | |
848 pkix_pl_HttpDefaultClient_RecvHdrContinue( | |
849 PKIX_PL_HttpDefaultClient *client, | |
850 PKIX_Boolean *pKeepGoing, | |
851 void *plContext) | |
852 { | |
853 PKIX_Int32 bytesRead = 0; | |
854 PKIX_PL_Socket_Callback *callbackList = NULL; | |
855 | |
856 PKIX_ENTER | |
857 (HTTPDEFAULTCLIENT, | |
858 "pkix_pl_HttpDefaultClient_RecvHdrContinue"); | |
859 PKIX_NULLCHECK_TWO(client, pKeepGoing); | |
860 | |
861 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
862 | |
863 PKIX_CHECK(callbackList->pollCallback | |
864 (client->socket, NULL, &bytesRead, plContext), | |
865 PKIX_SOCKETPOLLFAILED); | |
866 | |
867 if (bytesRead > 0) { | |
868 client->filledupBytes += bytesRead; | |
869 | |
870 PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete | |
871 (client, bytesRead, pKeepGoing, plContext), | |
872 PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED); | |
873 | |
874 } else { | |
875 | |
876 *pKeepGoing = PKIX_FALSE; | |
877 | |
878 } | |
879 | |
880 cleanup: | |
881 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
882 } | |
883 | |
884 /* | |
885 * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody | |
886 * DESCRIPTION: | |
887 * | |
888 * This function processes the contents of the first buffer of a received | |
889 * HTTP-protocol message for the HttpDefaultClient "client", and stores in | |
890 * "pKeepGoing" a flag indicating whether processing can continue without | |
891 * further input. | |
892 * | |
893 * PARAMETERS: | |
894 * "client" | |
895 * The address of the HttpDefaultClient object. Must be non-NULL. | |
896 * "pKeepGoing" | |
897 * The address at which the Boolean state machine flag is stored to | |
898 * indicate whether processing can continue without further input. | |
899 * Must be non-NULL. | |
900 * "plContext" | |
901 * Platform-specific context pointer. | |
902 * THREAD SAFETY: | |
903 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
904 * RETURNS: | |
905 * Returns NULL if the function succeeds. | |
906 * Returns a HttpDefaultClient Error if the function fails in a | |
907 * non-fatal way. | |
908 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
909 */ | |
910 static PKIX_Error * | |
911 pkix_pl_HttpDefaultClient_RecvBody( | |
912 PKIX_PL_HttpDefaultClient *client, | |
913 PKIX_Boolean *pKeepGoing, | |
914 void *plContext) | |
915 { | |
916 PKIX_Int32 bytesRead = 0; | |
917 PKIX_Int32 bytesToRead = 0; | |
918 PKIX_PL_Socket_Callback *callbackList = NULL; | |
919 | |
920 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody"); | |
921 PKIX_NULLCHECK_TWO(client, pKeepGoing); | |
922 | |
923 callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; | |
924 | |
925 if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) { | |
926 bytesToRead = client->rcv_http_data_len - | |
927 client->filledupBytes; | |
928 } else { | |
929 /* Reading till the EOF. Context length is not known.*/ | |
930 /* Check the buffer capacity: increase and | |
931 * reallocate if it is low. */ | |
932 int freeBuffSize = client->capacity - client->filledupBytes; | |
933 if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) { | |
934 /* New length will be consist of available(downloaded) bytes, | |
935 * plus remaining capacity, plus new expansion. */ | |
936 int currBuffSize = client->capacity; | |
937 /* Try to increase the buffer by 4K */ | |
938 int newLength = currBuffSize + HTTP_DATA_BUFSIZE; | |
939 if (client->maxResponseLen > 0 && | |
940 newLength > client->maxResponseLen) { | |
941 newLength = client->maxResponseLen; | |
942 } | |
943 /* Check if we can grow the buffer and report an error if | |
944 * new size is not larger than the current size of the buffer.*/ | |
945 if (newLength <= client->filledupBytes) { | |
946 client->rcv_http_data_len = client->filledupBytes; | |
947 client->connectStatus = HTTP_ERROR; | |
948 *pKeepGoing = PKIX_FALSE; | |
949 goto cleanup; | |
950 } | |
951 if (client->capacity < newLength) { | |
952 client->capacity = newLength; | |
953 PKIX_CHECK( | |
954 PKIX_PL_Realloc(client->rcvBuf, newLength, | |
955 (void**)&client->rcvBuf, plContext), | |
956 PKIX_REALLOCFAILED); | |
957 freeBuffSize = client->capacity - | |
958 client->filledupBytes; | |
959 } | |
960 } | |
961 bytesToRead = freeBuffSize; | |
962 } | |
963 | |
964 /* Use poll callback if waiting on non-blocking IO */ | |
965 if (client->connectStatus == HTTP_RECV_BODY_PENDING) { | |
966 PKIX_CHECK(callbackList->pollCallback | |
967 (client->socket, NULL, &bytesRead, plContext), | |
968 PKIX_SOCKETPOLLFAILED); | |
969 } else { | |
970 PKIX_CHECK(callbackList->recvCallback | |
971 (client->socket, | |
972 (void *)&(client->rcvBuf[client->filledupBytes]), | |
973 bytesToRead, | |
974 &bytesRead, | |
975 plContext), | |
976 PKIX_SOCKETRECVFAILED); | |
977 } | |
978 | |
979 /* If bytesRead < 0, an error will be thrown by recvCallback, so | |
980 * need to handle >= 0 cases. */ | |
981 | |
982 /* bytesRead == 0 - IO was blocked. */ | |
983 if (bytesRead == 0) { | |
984 client->connectStatus = HTTP_RECV_BODY_PENDING; | |
985 *pKeepGoing = PKIX_TRUE; | |
986 goto cleanup; | |
987 } | |
988 | |
989 /* We got something. Did we get it all? */ | |
990 client->filledupBytes += bytesRead; | |
991 | |
992 /* continue if not enough bytes read or if complete size of | |
993 * transfer is unknown */ | |
994 if (bytesToRead > bytesRead || | |
995 client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) { | |
996 *pKeepGoing = PKIX_TRUE; | |
997 goto cleanup; | |
998 } | |
999 client->connectStatus = HTTP_COMPLETE; | |
1000 *pKeepGoing = PKIX_FALSE; | |
1001 | |
1002 cleanup: | |
1003 if (pkixErrorResult && pkixErrorResult->errCode == | |
1004 PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) { | |
1005 if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) { | |
1006 client->rcv_http_data_len = client->filledupBytes; | |
1007 client->connectStatus = HTTP_COMPLETE; | |
1008 *pKeepGoing = PKIX_FALSE; | |
1009 PKIX_DECREF(pkixErrorResult); | |
1010 } else { | |
1011 client->connectStatus = HTTP_ERROR; | |
1012 } | |
1013 } | |
1014 | |
1015 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1016 } | |
1017 | |
1018 /* | |
1019 * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch | |
1020 * DESCRIPTION: | |
1021 * | |
1022 * This function is the state machine dispatcher for the HttpDefaultClient | |
1023 * pointed to by "client". Results are returned by changes to various fields | |
1024 * in the context. | |
1025 * | |
1026 * PARAMETERS: | |
1027 * "client" | |
1028 * The address of the HttpDefaultClient object. Must be non-NULL. | |
1029 * "plContext" | |
1030 * Platform-specific context pointer. | |
1031 * THREAD SAFETY: | |
1032 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
1033 * RETURNS: | |
1034 * Returns NULL if the function succeeds. | |
1035 * Returns a HttpDefaultClient Error if the function fails in a | |
1036 * non-fatal way. | |
1037 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
1038 */ | |
1039 static PKIX_Error * | |
1040 pkix_pl_HttpDefaultClient_Dispatch( | |
1041 PKIX_PL_HttpDefaultClient *client, | |
1042 void *plContext) | |
1043 { | |
1044 PKIX_UInt32 bytesTransferred = 0; | |
1045 PKIX_Boolean keepGoing = PKIX_TRUE; | |
1046 | |
1047 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch"); | |
1048 PKIX_NULLCHECK_ONE(client); | |
1049 | |
1050 while (keepGoing) { | |
1051 switch (client->connectStatus) { | |
1052 case HTTP_CONNECT_PENDING: | |
1053 PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue | |
1054 (client, &keepGoing, plContext), | |
1055 PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED); | |
1056 break; | |
1057 case HTTP_CONNECTED: | |
1058 PKIX_CHECK(pkix_pl_HttpDefaultClient_Send | |
1059 (client, &keepGoing, &bytesTransferred, plContext), | |
1060 PKIX_HTTPDEFAULTCLIENTSENDFAILED); | |
1061 break; | |
1062 case HTTP_SEND_PENDING: | |
1063 PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue | |
1064 (client, &keepGoing, &bytesTransferred, plContext), | |
1065 PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED); | |
1066 break; | |
1067 case HTTP_RECV_HDR: | |
1068 PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr | |
1069 (client, &keepGoing, plContext), | |
1070 PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED); | |
1071 break; | |
1072 case HTTP_RECV_HDR_PENDING: | |
1073 PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue | |
1074 (client, &keepGoing, plContext), | |
1075 PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED); | |
1076 break; | |
1077 case HTTP_RECV_BODY: | |
1078 case HTTP_RECV_BODY_PENDING: | |
1079 PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody | |
1080 (client, &keepGoing, plContext), | |
1081 PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED); | |
1082 break; | |
1083 case HTTP_ERROR: | |
1084 case HTTP_COMPLETE: | |
1085 keepGoing = PKIX_FALSE; | |
1086 break; | |
1087 case HTTP_NOT_CONNECTED: | |
1088 default: | |
1089 PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE); | |
1090 } | |
1091 } | |
1092 | |
1093 cleanup: | |
1094 | |
1095 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1096 } | |
1097 | |
1098 /* | |
1099 * --HttpClient vtable functions | |
1100 * See comments in ocspt.h for the function (wrappers) that return SECStatus. | |
1101 * The functions that return PKIX_Error* are the libpkix implementations. | |
1102 */ | |
1103 | |
1104 PKIX_Error * | |
1105 pkix_pl_HttpDefaultClient_CreateSession( | |
1106 const char *host, | |
1107 PRUint16 portnum, | |
1108 SEC_HTTP_SERVER_SESSION *pSession, | |
1109 void *plContext) | |
1110 { | |
1111 PKIX_PL_HttpDefaultClient *client = NULL; | |
1112 | |
1113 PKIX_ENTER | |
1114 (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession"); | |
1115 PKIX_NULLCHECK_TWO(host, pSession); | |
1116 | |
1117 PKIX_CHECK(pkix_pl_HttpDefaultClient_Create | |
1118 (host, portnum, &client, plContext), | |
1119 PKIX_HTTPDEFAULTCLIENTCREATEFAILED); | |
1120 | |
1121 *pSession = (SEC_HTTP_SERVER_SESSION)client; | |
1122 | |
1123 cleanup: | |
1124 | |
1125 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1126 | |
1127 } | |
1128 | |
1129 PKIX_Error * | |
1130 pkix_pl_HttpDefaultClient_KeepAliveSession( | |
1131 SEC_HTTP_SERVER_SESSION session, | |
1132 PRPollDesc **pPollDesc, | |
1133 void *plContext) | |
1134 { | |
1135 PKIX_PL_HttpDefaultClient *client = NULL; | |
1136 | |
1137 PKIX_ENTER | |
1138 (HTTPDEFAULTCLIENT, | |
1139 "pkix_pl_HttpDefaultClient_KeepAliveSession"); | |
1140 PKIX_NULLCHECK_TWO(session, pPollDesc); | |
1141 | |
1142 PKIX_CHECK(pkix_CheckType | |
1143 ((PKIX_PL_Object *)session, | |
1144 PKIX_HTTPDEFAULTCLIENT_TYPE, | |
1145 plContext), | |
1146 PKIX_SESSIONNOTANHTTPDEFAULTCLIENT); | |
1147 | |
1148 client = (PKIX_PL_HttpDefaultClient *)session; | |
1149 | |
1150 /* XXX Not implemented */ | |
1151 | |
1152 cleanup: | |
1153 | |
1154 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1155 | |
1156 } | |
1157 | |
1158 PKIX_Error * | |
1159 pkix_pl_HttpDefaultClient_RequestCreate( | |
1160 SEC_HTTP_SERVER_SESSION session, | |
1161 const char *http_protocol_variant, /* usually "http" */ | |
1162 const char *path_and_query_string, | |
1163 const char *http_request_method, | |
1164 const PRIntervalTime timeout, | |
1165 SEC_HTTP_REQUEST_SESSION *pRequest, | |
1166 void *plContext) | |
1167 { | |
1168 PKIX_PL_HttpDefaultClient *client = NULL; | |
1169 PKIX_PL_Socket *socket = NULL; | |
1170 PKIX_PL_Socket_Callback *callbackList = NULL; | |
1171 PRFileDesc *fileDesc = NULL; | |
1172 PRErrorCode status = 0; | |
1173 | |
1174 PKIX_ENTER | |
1175 (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate"); | |
1176 PKIX_NULLCHECK_TWO(session, pRequest); | |
1177 | |
1178 PKIX_CHECK(pkix_CheckType | |
1179 ((PKIX_PL_Object *)session, | |
1180 PKIX_HTTPDEFAULTCLIENT_TYPE, | |
1181 plContext), | |
1182 PKIX_SESSIONNOTANHTTPDEFAULTCLIENT); | |
1183 | |
1184 client = (PKIX_PL_HttpDefaultClient *)session; | |
1185 | |
1186 /* We only know how to do http */ | |
1187 if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) { | |
1188 PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED); | |
1189 } | |
1190 | |
1191 if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) { | |
1192 client->send_http_method = HTTP_POST_METHOD; | |
1193 } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) { | |
1194 client->send_http_method = HTTP_GET_METHOD; | |
1195 } else { | |
1196 /* We only know how to do POST and GET */ | |
1197 PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD); | |
1198 } | |
1199 | |
1200 if (path_and_query_string) { | |
1201 /* "path_and_query_string" is a parsing result by CERT_GetURL | |
1202 * function that adds "end of line" to the value. OK to dup | |
1203 * the string. */ | |
1204 client->path = PORT_Strdup(path_and_query_string); | |
1205 if (!client->path) { | |
1206 PKIX_ERROR(PKIX_ALLOCERROR); | |
1207 } | |
1208 } | |
1209 | |
1210 client->timeout = timeout; | |
1211 | |
1212 #if 0 | |
1213 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection | |
1214 (timeout, | |
1215 "variation.red.iplanet.com", /* (char *)client->host, */ | |
1216 2001, /* client->portnum, */ | |
1217 &status, | |
1218 &socket, | |
1219 plContext), | |
1220 PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); | |
1221 #else | |
1222 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection | |
1223 (timeout, | |
1224 (char *)client->host, | |
1225 client->portnum, | |
1226 &status, | |
1227 &socket, | |
1228 plContext), | |
1229 PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); | |
1230 #endif | |
1231 | |
1232 client->socket = socket; | |
1233 | |
1234 PKIX_CHECK(pkix_pl_Socket_GetCallbackList | |
1235 (socket, &callbackList, plContext), | |
1236 PKIX_SOCKETGETCALLBACKLISTFAILED); | |
1237 | |
1238 client->callbackList = (void *)callbackList; | |
1239 | |
1240 PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc | |
1241 (socket, &fileDesc, plContext), | |
1242 PKIX_SOCKETGETPRFILEDESCFAILED); | |
1243 | |
1244 client->pollDesc.fd = fileDesc; | |
1245 client->pollDesc.in_flags = 0; | |
1246 client->pollDesc.out_flags = 0; | |
1247 | |
1248 client->send_http_data = NULL; | |
1249 client->send_http_data_len = 0; | |
1250 client->send_http_content_type = NULL; | |
1251 | |
1252 client->connectStatus = | |
1253 ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING); | |
1254 | |
1255 /* Request object is the same object as Session object */ | |
1256 PKIX_INCREF(client); | |
1257 *pRequest = client; | |
1258 | |
1259 cleanup: | |
1260 | |
1261 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1262 | |
1263 } | |
1264 | |
1265 PKIX_Error * | |
1266 pkix_pl_HttpDefaultClient_SetPostData( | |
1267 SEC_HTTP_REQUEST_SESSION request, | |
1268 const char *http_data, | |
1269 const PRUint32 http_data_len, | |
1270 const char *http_content_type, | |
1271 void *plContext) | |
1272 { | |
1273 PKIX_PL_HttpDefaultClient *client = NULL; | |
1274 | |
1275 PKIX_ENTER | |
1276 (HTTPDEFAULTCLIENT, | |
1277 "pkix_pl_HttpDefaultClient_SetPostData"); | |
1278 PKIX_NULLCHECK_ONE(request); | |
1279 | |
1280 PKIX_CHECK(pkix_CheckType | |
1281 ((PKIX_PL_Object *)request, | |
1282 PKIX_HTTPDEFAULTCLIENT_TYPE, | |
1283 plContext), | |
1284 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); | |
1285 | |
1286 client = (PKIX_PL_HttpDefaultClient *)request; | |
1287 | |
1288 client->send_http_data = http_data; | |
1289 client->send_http_data_len = http_data_len; | |
1290 client->send_http_content_type = http_content_type; | |
1291 | |
1292 /* Caller is allowed to give NULL or empty string for content_type */ | |
1293 if ((client->send_http_content_type == NULL) || | |
1294 (*(client->send_http_content_type) == '\0')) { | |
1295 client->send_http_content_type = "application/ocsp-request"; | |
1296 } | |
1297 | |
1298 cleanup: | |
1299 | |
1300 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1301 | |
1302 } | |
1303 | |
1304 PKIX_Error * | |
1305 pkix_pl_HttpDefaultClient_TrySendAndReceive( | |
1306 SEC_HTTP_REQUEST_SESSION request, | |
1307 PRUint16 *http_response_code, | |
1308 const char **http_response_content_type, | |
1309 const char **http_response_headers, | |
1310 const char **http_response_data, | |
1311 PRUint32 *http_response_data_len, | |
1312 PRPollDesc **pPollDesc, | |
1313 SECStatus *pSECReturn, | |
1314 void *plContext) | |
1315 { | |
1316 PKIX_PL_HttpDefaultClient *client = NULL; | |
1317 PKIX_UInt32 postLen = 0; | |
1318 PRPollDesc *pollDesc = NULL; | |
1319 char *sendbuf = NULL; | |
1320 char portstr[16]; | |
1321 | |
1322 PKIX_ENTER | |
1323 (HTTPDEFAULTCLIENT, | |
1324 "pkix_pl_HttpDefaultClient_TrySendAndReceive"); | |
1325 | |
1326 PKIX_NULLCHECK_ONE(request); | |
1327 | |
1328 PKIX_CHECK(pkix_CheckType | |
1329 ((PKIX_PL_Object *)request, | |
1330 PKIX_HTTPDEFAULTCLIENT_TYPE, | |
1331 plContext), | |
1332 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); | |
1333 | |
1334 client = (PKIX_PL_HttpDefaultClient *)request; | |
1335 | |
1336 if (!pPollDesc && client->timeout == 0) { | |
1337 PKIX_ERROR_FATAL(PKIX_NULLARGUMENT); | |
1338 } | |
1339 | |
1340 if (pPollDesc) { | |
1341 pollDesc = *pPollDesc; | |
1342 } | |
1343 | |
1344 /* if not continuing from an earlier WOULDBLOCK return... */ | |
1345 if (pollDesc == NULL) { | |
1346 | |
1347 if (!((client->connectStatus == HTTP_CONNECTED) || | |
1348 (client->connectStatus == HTTP_CONNECT_PENDING))) { | |
1349 PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE); | |
1350 } | |
1351 | |
1352 /* Did caller provide a value for response length? */ | |
1353 if (http_response_data_len != NULL) { | |
1354 client->pRcv_http_data_len = http_response_data_len; | |
1355 client->maxResponseLen = *http_response_data_len; | |
1356 } | |
1357 | |
1358 client->rcv_http_response_code = http_response_code; | |
1359 client->rcv_http_content_type = http_response_content_type; | |
1360 client->rcv_http_headers = http_response_headers; | |
1361 client->rcv_http_data = http_response_data; | |
1362 | |
1363 /* prepare the message */ | |
1364 portstr[0] = '\0'; | |
1365 if (client->portnum != 80) { | |
1366 PR_snprintf(portstr, sizeof(portstr), ":%d", | |
1367 client->portnum); | |
1368 } | |
1369 | |
1370 if (client->send_http_method == HTTP_POST_METHOD) { | |
1371 sendbuf = PR_smprintf | |
1372 ("POST %s HTTP/1.0\r\nHost: %s%s\r\n" | |
1373 "Content-Type: %s\r\nContent-Length: %u\r\n\r\n", | |
1374 client->path, | |
1375 client->host, | |
1376 portstr, | |
1377 client->send_http_content_type, | |
1378 client->send_http_data_len); | |
1379 postLen = PORT_Strlen(sendbuf); | |
1380 | |
1381 client->POSTLen = postLen + client->send_http_data_len; | |
1382 | |
1383 /* allocate postBuffer big enough for header + data */ | |
1384 PKIX_CHECK(PKIX_PL_Malloc | |
1385 (client->POSTLen, | |
1386 (void **)&(client->POSTBuf), | |
1387 plContext), | |
1388 PKIX_MALLOCFAILED); | |
1389 | |
1390 /* copy header into postBuffer */ | |
1391 PORT_Memcpy(client->POSTBuf, sendbuf, postLen); | |
1392 | |
1393 /* append data after header */ | |
1394 PORT_Memcpy(&client->POSTBuf[postLen], | |
1395 client->send_http_data, | |
1396 client->send_http_data_len); | |
1397 | |
1398 /* PR_smprintf_free original header buffer */ | |
1399 PR_smprintf_free(sendbuf); | |
1400 sendbuf = NULL; | |
1401 | |
1402 } else if (client->send_http_method == HTTP_GET_METHOD) { | |
1403 client->GETBuf = PR_smprintf | |
1404 ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n", | |
1405 client->path, | |
1406 client->host, | |
1407 portstr); | |
1408 client->GETLen = PORT_Strlen(client->GETBuf); | |
1409 } | |
1410 | |
1411 } | |
1412 | |
1413 /* continue according to state */ | |
1414 PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plContext), | |
1415 PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED); | |
1416 | |
1417 switch (client->connectStatus) { | |
1418 case HTTP_CONNECT_PENDING: | |
1419 case HTTP_SEND_PENDING: | |
1420 case HTTP_RECV_HDR_PENDING: | |
1421 case HTTP_RECV_BODY_PENDING: | |
1422 pollDesc = &(client->pollDesc); | |
1423 *pSECReturn = SECWouldBlock; | |
1424 break; | |
1425 case HTTP_ERROR: | |
1426 /* Did caller provide a pointer for length? */ | |
1427 if (client->pRcv_http_data_len != NULL) { | |
1428 /* Was error "response too big?" */ | |
1429 if (client->rcv_http_data_len != | |
1430 HTTP_UNKNOWN_CONTENT_LENGTH && | |
1431 client->maxResponseLen >= | |
1432 client->rcv_http_data_len) { | |
1433 /* Yes, report needed space */ | |
1434 *(client->pRcv_http_data_len) = | |
1435 client->rcv_http_data_len; | |
1436 } else { | |
1437 /* No, report problem other than size */ | |
1438 *(client->pRcv_http_data_len) = 0; | |
1439 } | |
1440 } | |
1441 | |
1442 pollDesc = NULL; | |
1443 *pSECReturn = SECFailure; | |
1444 break; | |
1445 case HTTP_COMPLETE: | |
1446 *(client->rcv_http_response_code) = | |
1447 client->responseCode; | |
1448 if (client->pRcv_http_data_len != NULL) { | |
1449 *http_response_data_len = | |
1450 client->rcv_http_data_len; | |
1451 } | |
1452 if (client->rcv_http_data != NULL) { | |
1453 *(client->rcv_http_data) = client->rcvBuf; | |
1454 } | |
1455 pollDesc = NULL; | |
1456 *pSECReturn = SECSuccess; | |
1457 break; | |
1458 case HTTP_NOT_CONNECTED: | |
1459 case HTTP_CONNECTED: | |
1460 case HTTP_RECV_HDR: | |
1461 case HTTP_RECV_BODY: | |
1462 default: | |
1463 pollDesc = NULL; | |
1464 *pSECReturn = SECFailure; | |
1465 PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE); | |
1466 break; | |
1467 } | |
1468 | |
1469 if (pPollDesc) { | |
1470 *pPollDesc = pollDesc; | |
1471 } | |
1472 | |
1473 cleanup: | |
1474 if (sendbuf) { | |
1475 PR_smprintf_free(sendbuf); | |
1476 } | |
1477 | |
1478 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1479 | |
1480 } | |
1481 | |
1482 PKIX_Error * | |
1483 pkix_pl_HttpDefaultClient_Cancel( | |
1484 SEC_HTTP_REQUEST_SESSION request, | |
1485 void *plContext) | |
1486 { | |
1487 PKIX_PL_HttpDefaultClient *client = NULL; | |
1488 | |
1489 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel"); | |
1490 PKIX_NULLCHECK_ONE(request); | |
1491 | |
1492 PKIX_CHECK(pkix_CheckType | |
1493 ((PKIX_PL_Object *)request, | |
1494 PKIX_HTTPDEFAULTCLIENT_TYPE, | |
1495 plContext), | |
1496 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); | |
1497 | |
1498 client = (PKIX_PL_HttpDefaultClient *)request; | |
1499 | |
1500 /* XXX Not implemented */ | |
1501 | |
1502 cleanup: | |
1503 | |
1504 PKIX_RETURN(HTTPDEFAULTCLIENT); | |
1505 | |
1506 } | |
1507 | |
1508 SECStatus | |
1509 pkix_pl_HttpDefaultClient_CreateSessionFcn( | |
1510 const char *host, | |
1511 PRUint16 portnum, | |
1512 SEC_HTTP_SERVER_SESSION *pSession) | |
1513 { | |
1514 PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession | |
1515 (host, portnum, pSession, plContext); | |
1516 | |
1517 if (err) { | |
1518 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1519 return SECFailure; | |
1520 } | |
1521 return SECSuccess; | |
1522 } | |
1523 | |
1524 SECStatus | |
1525 pkix_pl_HttpDefaultClient_KeepAliveSessionFcn( | |
1526 SEC_HTTP_SERVER_SESSION session, | |
1527 PRPollDesc **pPollDesc) | |
1528 { | |
1529 PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession | |
1530 (session, pPollDesc, plContext); | |
1531 | |
1532 if (err) { | |
1533 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1534 return SECFailure; | |
1535 } | |
1536 return SECSuccess; | |
1537 } | |
1538 | |
1539 SECStatus | |
1540 pkix_pl_HttpDefaultClient_FreeSessionFcn( | |
1541 SEC_HTTP_SERVER_SESSION session) | |
1542 { | |
1543 PKIX_Error *err = | |
1544 PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext); | |
1545 | |
1546 if (err) { | |
1547 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1548 return SECFailure; | |
1549 } | |
1550 return SECSuccess; | |
1551 } | |
1552 | |
1553 SECStatus | |
1554 pkix_pl_HttpDefaultClient_RequestCreateFcn( | |
1555 SEC_HTTP_SERVER_SESSION session, | |
1556 const char *http_protocol_variant, /* usually "http" */ | |
1557 const char *path_and_query_string, | |
1558 const char *http_request_method, | |
1559 const PRIntervalTime timeout, | |
1560 SEC_HTTP_REQUEST_SESSION *pRequest) | |
1561 { | |
1562 PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate | |
1563 (session, | |
1564 http_protocol_variant, | |
1565 path_and_query_string, | |
1566 http_request_method, | |
1567 timeout, | |
1568 pRequest, | |
1569 plContext); | |
1570 | |
1571 if (err) { | |
1572 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1573 return SECFailure; | |
1574 } | |
1575 return SECSuccess; | |
1576 } | |
1577 | |
1578 SECStatus | |
1579 pkix_pl_HttpDefaultClient_SetPostDataFcn( | |
1580 SEC_HTTP_REQUEST_SESSION request, | |
1581 const char *http_data, | |
1582 const PRUint32 http_data_len, | |
1583 const char *http_content_type) | |
1584 { | |
1585 PKIX_Error *err = | |
1586 pkix_pl_HttpDefaultClient_SetPostData(request, http_data, | |
1587 http_data_len, | |
1588 http_content_type, | |
1589 plContext); | |
1590 if (err) { | |
1591 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1592 return SECFailure; | |
1593 } | |
1594 return SECSuccess; | |
1595 } | |
1596 | |
1597 SECStatus | |
1598 pkix_pl_HttpDefaultClient_AddHeaderFcn( | |
1599 SEC_HTTP_REQUEST_SESSION request, | |
1600 const char *http_header_name, | |
1601 const char *http_header_value) | |
1602 { | |
1603 /* Not supported */ | |
1604 return SECFailure; | |
1605 } | |
1606 | |
1607 SECStatus | |
1608 pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn( | |
1609 SEC_HTTP_REQUEST_SESSION request, | |
1610 PRPollDesc **pPollDesc, | |
1611 PRUint16 *http_response_code, | |
1612 const char **http_response_content_type, | |
1613 const char **http_response_headers, | |
1614 const char **http_response_data, | |
1615 PRUint32 *http_response_data_len) | |
1616 { | |
1617 SECStatus rv = SECFailure; | |
1618 | |
1619 PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive | |
1620 (request, | |
1621 http_response_code, | |
1622 http_response_content_type, | |
1623 http_response_headers, | |
1624 http_response_data, | |
1625 http_response_data_len, | |
1626 pPollDesc, | |
1627 &rv, | |
1628 plContext); | |
1629 | |
1630 if (err) { | |
1631 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1632 return rv; | |
1633 } | |
1634 return SECSuccess; | |
1635 } | |
1636 | |
1637 SECStatus | |
1638 pkix_pl_HttpDefaultClient_CancelFcn( | |
1639 SEC_HTTP_REQUEST_SESSION request) | |
1640 { | |
1641 PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext); | |
1642 | |
1643 if (err) { | |
1644 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1645 return SECFailure; | |
1646 } | |
1647 return SECSuccess; | |
1648 } | |
1649 | |
1650 SECStatus | |
1651 pkix_pl_HttpDefaultClient_FreeFcn( | |
1652 SEC_HTTP_REQUEST_SESSION request) | |
1653 { | |
1654 PKIX_Error *err = | |
1655 PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext); | |
1656 | |
1657 if (err) { | |
1658 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); | |
1659 return SECFailure; | |
1660 } | |
1661 return SECSuccess; | |
1662 } |