PageRenderTime 40ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/globus_gass_transfer-7.2/library/globus_gass_transfer_http.c

#
C | 6483 lines | 5093 code | 648 blank | 742 comment | 687 complexity | de1586f4ef60c82a9264f1084549746c MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. * Copyright 1999-2006 University of Chicago
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
  17. /**
  18. * @file globus_gass_transfer_http.c http/https Protocol Module Implementation
  19. *
  20. * This module implements the http and https URL schemes for the GASS transfer
  21. * library
  22. *
  23. * CVS Information:
  24. * $Source: /home/globdev/CVS/globus-packages/gass/transfer/source/library/globus_gass_transfer_http.c,v $
  25. * $Date: 2009/11/11 19:48:37 $
  26. * $Revision: 1.48 $
  27. * $Author: bester $
  28. */
  29. #endif
  30. #include "globus_i_gass_transfer.h"
  31. #include "globus_io.h"
  32. #include "globus_l_gass_transfer_http.h"
  33. #include <stdlib.h>
  34. #include <ctype.h>
  35. #include <string.h>
  36. #ifndef TARGET_ARCH_WIN32
  37. #include <strings.h>
  38. #endif
  39. #include "version.h"
  40. #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
  41. /*
  42. #define DEBUG_GASS_TRANSFER
  43. */
  44. typedef struct
  45. {
  46. globus_gass_transfer_http_listener_proto_t * l_proto;
  47. globus_gass_transfer_request_t request;
  48. }
  49. globus_l_gass_transfer_failed_kickout_closure_t;
  50. #if defined(DEBUG_GASS_TRANSFER)
  51. static char * globus_l_gass_transfer_http_debug_level="";
  52. /* Debug Levels */
  53. /* 1: Major entry points to the library are displayed */
  54. /* 2: Calls into the gass transfer proto API are displayed */
  55. /* 3: Callbacks are displayed */
  56. /* 4: Callback Registration is displayed */
  57. /* 5: Error returns from lower-level calls */
  58. /* 6: Protocol dumps */
  59. /* 9: Thread safety */
  60. #define debug_printf(level,fmt) \
  61. if(strchr(globus_l_gass_transfer_http_debug_level, (#level)[0])) \
  62. {\
  63. printf fmt;\
  64. }
  65. #undef globus_l_gass_transfer_http_lock
  66. #undef globus_l_gass_transfer_http_unlock
  67. static int globus_l_gass_lock_line=0;
  68. static int globus_l_gass_lock_tmp=0;
  69. #define MYNAME(x) static char * myname=#x
  70. #define globus_l_gass_transfer_http_lock() \
  71. printf(strchr(globus_l_gass_transfer_http_debug_level,'9') ? "Thread [%d] acquiring mutex at %s:%d\n" : "", \
  72. (int) globus_thread_self(), \
  73. __FILE__, \
  74. __LINE__), \
  75. fflush(stdout), \
  76. globus_l_gass_lock_tmp = \
  77. globus_mutex_lock(&globus_l_gass_transfer_http_mutex), \
  78. globus_l_gass_lock_line=__LINE__, \
  79. globus_l_gass_lock_tmp
  80. #define globus_l_gass_transfer_http_unlock() \
  81. printf(strchr(globus_l_gass_transfer_http_debug_level, '9') ? "Thread [%d] releasing mutex at %s:%d\n" : "", \
  82. (int) globus_thread_self(), \
  83. __FILE__, \
  84. __LINE__), \
  85. fflush(stdout), \
  86. globus_l_gass_lock_line = 0, \
  87. globus_mutex_unlock(&globus_l_gass_transfer_http_mutex)
  88. #else
  89. #define debug_printf(level, fmt)
  90. #define MYNAME(x)
  91. #endif
  92. static
  93. void
  94. globus_l_gass_transfer_http_accept_failed_kickout(
  95. void * arg);
  96. static volatile int globus_l_gass_transfer_http_closing;
  97. #if !defined(GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST)
  98. int
  99. globus_l_gass_transfer_http_activate(void)
  100. {
  101. OM_uint32 maj_stat;
  102. OM_uint32 min_stat;
  103. gss_name_t name;
  104. gss_cred_id_t globus_l_gass_transfer_http_credential =
  105. GSS_C_NO_CREDENTIAL;
  106. gss_buffer_desc name_buffer;
  107. MYNAME(globus_l_gass_transfer_http_activate);
  108. globus_l_gass_transfer_http_closing = 0;
  109. name_buffer.value = GLOBUS_NULL;
  110. name_buffer.length = 0;
  111. # if defined(DEBUG_GASS_TRANSFER)
  112. {
  113. globus_l_gass_transfer_http_debug_level =
  114. globus_module_getenv("GLOBUS_GASS_TRANSFER_HTTP_DEBUG_LEVEL");
  115. if(globus_l_gass_transfer_http_debug_level == GLOBUS_NULL)
  116. {
  117. globus_l_gass_transfer_http_debug_level = "";
  118. }
  119. }
  120. # endif
  121. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  122. globus_module_activate(GLOBUS_COMMON_MODULE);
  123. globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE);
  124. globus_module_activate(GLOBUS_IO_MODULE);
  125. globus_mutex_init(&globus_l_gass_transfer_http_mutex,
  126. GLOBUS_NULL);
  127. globus_cond_init(&globus_l_gass_transfer_http_cond,
  128. GLOBUS_NULL);
  129. maj_stat = globus_gss_assist_acquire_cred(
  130. &min_stat,
  131. GSS_C_BOTH,
  132. &globus_l_gass_transfer_http_credential);
  133. if (maj_stat != GSS_S_COMPLETE)
  134. {
  135. goto error_exit;
  136. }
  137. maj_stat = gss_inquire_cred(
  138. &min_stat,
  139. globus_l_gass_transfer_http_credential,
  140. &name,
  141. GLOBUS_NULL,
  142. GLOBUS_NULL,
  143. GLOBUS_NULL);
  144. if (maj_stat != GSS_S_COMPLETE)
  145. {
  146. goto error_exit;
  147. }
  148. maj_stat = gss_display_name(
  149. &min_stat,
  150. name,
  151. &name_buffer,
  152. GLOBUS_NULL);
  153. if (maj_stat != GSS_S_COMPLETE)
  154. {
  155. goto error_exit;
  156. }
  157. maj_stat = gss_release_name(
  158. &min_stat,
  159. &name);
  160. if (maj_stat != GSS_S_COMPLETE)
  161. {
  162. goto error_exit;
  163. }
  164. globus_l_gass_transfer_http_subject_name = name_buffer.value;
  165. if (globus_l_gass_transfer_http_credential != GSS_C_NO_CREDENTIAL)
  166. {
  167. gss_release_cred(&min_stat, &globus_l_gass_transfer_http_credential);
  168. }
  169. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  170. return GLOBUS_SUCCESS;
  171. error_exit:
  172. if (globus_l_gass_transfer_http_credential != GSS_C_NO_CREDENTIAL)
  173. {
  174. gss_release_cred(&min_stat, &globus_l_gass_transfer_http_credential);
  175. }
  176. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  177. return GLOBUS_FAILURE;
  178. }
  179. int
  180. globus_l_gass_transfer_http_deactivate(void)
  181. {
  182. MYNAME(globus_l_gass_transfer_http_deactivate);
  183. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  184. globus_l_gass_transfer_http_lock();
  185. while(globus_l_gass_transfer_http_closing > 0)
  186. {
  187. globus_l_gass_transfer_http_wait();
  188. }
  189. globus_l_gass_transfer_http_unlock();
  190. globus_module_deactivate(GLOBUS_IO_MODULE);
  191. globus_module_deactivate(GLOBUS_GSI_GSS_ASSIST_MODULE);
  192. globus_mutex_destroy(&globus_l_gass_transfer_http_mutex);
  193. globus_cond_destroy(&globus_l_gass_transfer_http_cond);
  194. globus_free(globus_l_gass_transfer_http_subject_name);
  195. globus_module_deactivate(GLOBUS_COMMON_MODULE);
  196. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  197. return GLOBUS_SUCCESS;
  198. }
  199. globus_module_descriptor_t globus_i_gass_transfer_http_module =
  200. {
  201. "globus_i_gass_transfer_http",
  202. globus_l_gass_transfer_http_activate,
  203. globus_l_gass_transfer_http_deactivate,
  204. GLOBUS_NULL,
  205. GLOBUS_NULL,
  206. &local_version
  207. };
  208. /* Protocol Descriptor, which is registered with the GASS system */
  209. globus_gass_transfer_proto_descriptor_t
  210. globus_i_gass_transfer_http_descriptor =
  211. {
  212. "http",
  213. /* client-side support */
  214. globus_l_gass_transfer_http_new_requestattr,
  215. globus_l_gass_transfer_http_new_request,
  216. /* server-side support */
  217. globus_l_gass_transfer_http_new_listenerattr /* new_listenerattr */,
  218. globus_l_gass_transfer_http_new_listener /* new_listener */
  219. };
  220. globus_gass_transfer_proto_descriptor_t
  221. globus_i_gass_transfer_https_descriptor =
  222. {
  223. "https",
  224. /* client-side support */
  225. globus_l_gass_transfer_http_new_requestattr,
  226. globus_l_gass_transfer_http_new_request,
  227. /* server-side support */
  228. globus_l_gass_transfer_http_new_listenerattr /* new_listenerattr */,
  229. globus_l_gass_transfer_http_new_listener /* new_listener */
  230. };
  231. /*
  232. * Function: globus_l_gass_transfer_http_send()
  233. *
  234. * Description: Send a byte array to an HTTP server
  235. *
  236. * Parameters:
  237. *
  238. * Returns:
  239. */
  240. static
  241. void
  242. globus_l_gass_transfer_http_send(
  243. globus_gass_transfer_request_proto_t * proto,
  244. globus_gass_transfer_request_t request,
  245. globus_byte_t * buffer,
  246. globus_size_t buffer_length,
  247. globus_bool_t last_data)
  248. {
  249. globus_result_t result;
  250. globus_gass_transfer_http_request_proto_t * new_proto;
  251. globus_reltime_t delay_time;
  252. MYNAME(globus_l_gass_transfer_http_send);
  253. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  254. globus_l_gass_transfer_http_lock();
  255. new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
  256. new_proto->last_data = last_data;
  257. /* We can only process a send if the proto is in the "idle" state */
  258. globus_assert(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE);
  259. /* state change to "pending" */
  260. new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING;
  261. /* Update the buffers to point to those supplied by the user */
  262. new_proto->user_buffer = buffer;
  263. new_proto->user_buflen = buffer_length;
  264. /* If a a failure occurred, callback with the failure bit set,
  265. * and close the handle
  266. */
  267. if(new_proto->failure_occurred)
  268. {
  269. goto fail_exit;
  270. }
  271. /* Register the send of the data */
  272. if(new_proto->chunked)
  273. {
  274. globus_size_t num_iovecs;
  275. /* send chunk header and footer as an iovec array */
  276. sprintf((char *) new_proto->iov[0].iov_base,
  277. "%lx%s",
  278. (long) new_proto->user_buflen,
  279. CRLF);
  280. new_proto->iov[0].iov_len = strlen((char *) new_proto->iov[0].iov_base);
  281. new_proto->iov[1].iov_base = (void *) new_proto->user_buffer;
  282. new_proto->iov[1].iov_len = new_proto->user_buflen;
  283. new_proto->iov[2].iov_base = CRLF;
  284. new_proto->iov[2].iov_len = 2;
  285. if(last_data && new_proto->user_buflen != 0)
  286. {
  287. /* last data, need to append a zero-length chunk to
  288. * indicate this
  289. */
  290. num_iovecs = 4;
  291. }
  292. else if(last_data && new_proto->user_buflen == 0)
  293. {
  294. /* last data, with a zero-length chunk from the user */
  295. new_proto->iov[1].iov_base = CRLF;
  296. new_proto->iov[1].iov_len = 2;
  297. num_iovecs = 2;
  298. }
  299. else
  300. {
  301. /* normal chunk */
  302. num_iovecs = 3;
  303. }
  304. debug_printf(4, (_GTSL("%s(): Registering writev\n"), myname));
  305. result = globus_io_register_writev(
  306. &new_proto->handle,
  307. new_proto->iov,
  308. num_iovecs /* 3 iovecs header, body, final CRLF */,
  309. globus_l_gass_transfer_http_writev_callback,
  310. new_proto);
  311. }
  312. else
  313. {
  314. /* send data raw */
  315. debug_printf(4, (_GTSL("%s(): Registering writev\n"), myname));
  316. result = globus_io_register_write(
  317. &new_proto->handle,
  318. new_proto->user_buffer,
  319. new_proto->user_buflen,
  320. globus_l_gass_transfer_http_write_callback,
  321. new_proto);
  322. }
  323. if(result == GLOBUS_SUCCESS)
  324. {
  325. /*
  326. * Registration succeeded. Callback to GASS occurs when I/O
  327. * completes.
  328. */
  329. globus_l_gass_transfer_http_unlock();
  330. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  331. return;
  332. }
  333. fail_exit:
  334. /* Registration failed, close up handle and signal failure to GASS */
  335. result = globus_l_gass_transfer_http_register_close(new_proto);
  336. if (result != GLOBUS_SUCCESS)
  337. {
  338. globus_l_gass_transfer_http_close(new_proto);
  339. }
  340. GlobusTimeReltimeSet(delay_time, 0, 0);
  341. debug_printf(4, (_GTSL("%s(): Registering oneshot\n"), myname));
  342. globus_callback_register_oneshot(
  343. GLOBUS_NULL,
  344. &delay_time,
  345. globus_l_gass_transfer_http_callback_send_callback,
  346. (void *) new_proto);
  347. globus_l_gass_transfer_http_unlock();
  348. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  349. }
  350. /* globus_l_gass_transfer_http_send() */
  351. /*
  352. * Function: globus_l_gass_transfer_http_receive()
  353. *
  354. * Description: Schedule the next block of data from the http server
  355. * to end up in the provided byte array
  356. *
  357. * Parameters:
  358. *
  359. * Returns:
  360. */
  361. static
  362. void
  363. globus_l_gass_transfer_http_receive(
  364. globus_gass_transfer_request_proto_t * proto,
  365. globus_gass_transfer_request_t request,
  366. globus_byte_t * buffer,
  367. globus_size_t buffer_length,
  368. globus_size_t wait_for_length)
  369. {
  370. globus_gass_transfer_http_request_proto_t * new_proto;
  371. globus_reltime_t delay_time;
  372. MYNAME(globus_l_gass_transfer_http_receive);
  373. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  374. globus_l_gass_transfer_http_lock();
  375. new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
  376. /* We can only process a receive if the proto is in the "idle" state */
  377. globus_assert(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE);
  378. /* state change to "pending" */
  379. new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING;
  380. /* Update the buffers to point to those supplied by the user */
  381. new_proto->user_buffer = buffer;
  382. new_proto->user_buflen = buffer_length;
  383. new_proto->user_offset = 0;
  384. new_proto->user_waitlen = wait_for_length;
  385. new_proto->oneshot_registered = GLOBUS_TRUE;
  386. GlobusTimeReltimeSet(delay_time, 0, 0);
  387. debug_printf(4, (_GTSL("%s(): Registering oneshot\n"), myname));
  388. globus_callback_register_oneshot(
  389. GLOBUS_NULL,
  390. &delay_time,
  391. globus_l_gass_transfer_http_callback_read_buffered_callback,
  392. (void *) new_proto);
  393. globus_l_gass_transfer_http_unlock();
  394. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  395. }
  396. /* globus_l_gass_transfer_http_receive() */
  397. /*
  398. * Function: globus_l_gass_transfer_http_fail()
  399. *
  400. * Description: Cause the given request to fail for client-caused reasons
  401. *
  402. * Parameters:
  403. *
  404. * Returns:
  405. */
  406. static
  407. void
  408. globus_l_gass_transfer_http_fail(
  409. globus_gass_transfer_request_proto_t * proto,
  410. globus_gass_transfer_request_t request)
  411. {
  412. globus_gass_transfer_http_request_proto_t * new_proto;
  413. globus_bool_t signalled;
  414. globus_result_t result;
  415. MYNAME(globus_l_gass_transfer_http_fail);
  416. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  417. new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
  418. globus_l_gass_transfer_http_lock();
  419. signalled = GLOBUS_FALSE;
  420. while(!signalled)
  421. {
  422. switch(new_proto->state)
  423. {
  424. case GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING:
  425. if(new_proto->oneshot_registered == GLOBUS_TRUE)
  426. {
  427. new_proto->failure_occurred = GLOBUS_TRUE;
  428. signalled = GLOBUS_TRUE;
  429. break;
  430. }
  431. else if(new_proto->oneshot_active)
  432. {
  433. new_proto->failure_occurred = GLOBUS_TRUE;
  434. while(new_proto->state ==
  435. GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
  436. {
  437. globus_l_gass_transfer_http_wait();
  438. }
  439. break;
  440. }
  441. case GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING:
  442. case GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE:
  443. /* We will transition to the closing state, signalling the failure,
  444. * and registering the close (which will transition us to the
  445. * done state).
  446. */
  447. signalled = GLOBUS_TRUE;
  448. new_proto->failure_occurred = GLOBUS_TRUE;
  449. result = globus_l_gass_transfer_http_register_close(new_proto);
  450. if (result != GLOBUS_SUCCESS)
  451. {
  452. globus_l_gass_transfer_http_close(new_proto);
  453. }
  454. break;
  455. case GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING:
  456. case GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE:
  457. case GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING:
  458. case GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING:
  459. case GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED:
  460. case GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED:
  461. signalled = GLOBUS_TRUE;
  462. new_proto->failure_occurred = GLOBUS_TRUE;
  463. break;
  464. }
  465. }
  466. globus_l_gass_transfer_http_unlock();
  467. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  468. }
  469. /* globus_l_gass_transfer_http_fail() */
  470. static
  471. void
  472. globus_l_gass_transfer_http_write_callback(
  473. void * callback_arg,
  474. globus_io_handle_t * handle,
  475. globus_result_t result,
  476. globus_byte_t * buf,
  477. globus_size_t nbytes)
  478. {
  479. globus_gass_transfer_http_request_proto_t * proto;
  480. MYNAME(globus_l_gass_transfer_http_write_callback);
  481. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  482. proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
  483. globus_l_gass_transfer_http_lock();
  484. if(result != GLOBUS_SUCCESS ||
  485. proto->failure_occurred ||
  486. proto->parse_error)
  487. {
  488. proto->last_data = GLOBUS_TRUE;
  489. }
  490. if(proto->last_data)
  491. {
  492. proto->user_offset = nbytes;
  493. if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  494. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
  495. (!proto->failure_occurred && !proto->parse_error))
  496. {
  497. if(proto->got_response)
  498. {
  499. globus_byte_t * buffer;
  500. globus_size_t offset;
  501. globus_gass_transfer_request_t request = proto->request;
  502. int failed = proto->failure_occurred;
  503. proto->failure_occurred = GLOBUS_TRUE;
  504. buffer = proto->user_buffer;
  505. offset = proto->user_offset;
  506. result = globus_l_gass_transfer_http_register_close(proto);
  507. if (result != GLOBUS_SUCCESS)
  508. {
  509. globus_l_gass_transfer_http_close(proto);
  510. }
  511. globus_l_gass_transfer_http_unlock();
  512. globus_gass_transfer_proto_send_complete(request,
  513. buffer,
  514. offset,
  515. failed,
  516. GLOBUS_TRUE);
  517. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  518. return;
  519. }
  520. else
  521. {
  522. /* the callback to read the response is registered at
  523. * the beginning of the send, so we do nothing here,
  524. * and wait for the response
  525. */
  526. proto->waiting_for_response = GLOBUS_TRUE;
  527. globus_l_gass_transfer_http_unlock();
  528. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  529. return;
  530. }
  531. }
  532. else
  533. {
  534. globus_gass_transfer_request_t request;
  535. globus_byte_t * buf;
  536. globus_size_t nbytes_sent;
  537. globus_bool_t fail;
  538. request = proto->request;
  539. buf = proto->user_buffer;
  540. nbytes_sent = proto->user_offset;
  541. fail = proto->failure_occurred;
  542. /* need to register the close, and callback to the user */
  543. result = globus_l_gass_transfer_http_register_close(proto);
  544. if (result != GLOBUS_SUCCESS)
  545. {
  546. globus_l_gass_transfer_http_close(proto);
  547. }
  548. globus_l_gass_transfer_http_unlock();
  549. globus_gass_transfer_proto_send_complete(
  550. request,
  551. buf,
  552. nbytes_sent,
  553. fail,
  554. GLOBUS_TRUE);
  555. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  556. return;
  557. }
  558. }
  559. else
  560. {
  561. globus_gass_transfer_request_t request;
  562. globus_byte_t * buf;
  563. globus_bool_t fail;
  564. globus_bool_t last_data;
  565. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  566. request = proto->request;
  567. buf = proto->user_buffer;
  568. fail = proto->failure_occurred;
  569. last_data = proto->last_data;
  570. globus_l_gass_transfer_http_unlock();
  571. globus_gass_transfer_proto_send_complete(request,
  572. buf,
  573. nbytes,
  574. fail,
  575. last_data);
  576. }
  577. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  578. return;
  579. }
  580. /* globus_l_gass_transfer_http_write_callback() */
  581. static
  582. void
  583. globus_l_gass_transfer_http_writev_callback(
  584. void * callback_arg,
  585. globus_io_handle_t * handle,
  586. globus_result_t result,
  587. struct iovec * iov,
  588. globus_size_t iovcnt,
  589. globus_size_t nbytes)
  590. {
  591. globus_gass_transfer_http_request_proto_t * proto;
  592. MYNAME(globus_l_gass_transfer_http_writev_callback);
  593. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  594. proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
  595. globus_l_gass_transfer_http_lock();
  596. if(result != GLOBUS_SUCCESS ||
  597. proto->failure_occurred ||
  598. proto->parse_error)
  599. {
  600. proto->last_data = GLOBUS_TRUE;
  601. }
  602. if(proto->last_data)
  603. {
  604. proto->user_offset = nbytes - iov[0].iov_len - iov[2].iov_len;
  605. if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  606. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
  607. (!proto->failure_occurred && !proto->parse_error))
  608. {
  609. if(proto->got_response)
  610. {
  611. globus_byte_t * buffer;
  612. globus_size_t offset;
  613. int failed = proto->failure_occurred;
  614. globus_gass_transfer_request_t request = proto->request;
  615. buffer = proto->user_buffer;
  616. offset = proto->user_offset;
  617. result = globus_l_gass_transfer_http_register_close(proto);
  618. if (result != GLOBUS_SUCCESS)
  619. {
  620. globus_l_gass_transfer_http_close(proto);
  621. }
  622. globus_l_gass_transfer_http_unlock();
  623. globus_gass_transfer_proto_send_complete(request,
  624. buffer,
  625. offset,
  626. failed,
  627. GLOBUS_TRUE);
  628. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  629. return;
  630. }
  631. else
  632. {
  633. /* the callback to read the response is registered at
  634. * the beginning of the send, so we do nothing here,
  635. * and wait for the response
  636. */
  637. proto->waiting_for_response = GLOBUS_TRUE;
  638. globus_l_gass_transfer_http_unlock();
  639. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  640. return;
  641. }
  642. }
  643. else
  644. {
  645. globus_gass_transfer_request_t request;
  646. globus_byte_t *buf;
  647. globus_size_t nbytes_sent;
  648. globus_bool_t fail;
  649. request = proto->request;
  650. buf = proto->user_buffer;
  651. nbytes_sent = proto->user_offset;
  652. fail = proto->failure_occurred;
  653. /* need to register the close, and callback to the user */
  654. result = globus_l_gass_transfer_http_register_close(proto);
  655. if (result != GLOBUS_SUCCESS)
  656. {
  657. globus_l_gass_transfer_http_close(proto);
  658. }
  659. globus_l_gass_transfer_http_unlock();
  660. globus_gass_transfer_proto_send_complete(
  661. request,
  662. buf,
  663. nbytes_sent,
  664. fail,
  665. GLOBUS_TRUE);
  666. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  667. return;
  668. }
  669. }
  670. else
  671. {
  672. globus_gass_transfer_request_t request;
  673. globus_byte_t *buf;
  674. globus_size_t nbytes_sent;
  675. globus_bool_t fail;
  676. request = proto->request;
  677. buf = proto->user_buffer;
  678. nbytes_sent = nbytes - iov[0].iov_len - iov[2].iov_len,
  679. fail = proto->failure_occurred;
  680. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  681. globus_l_gass_transfer_http_unlock();
  682. globus_gass_transfer_proto_send_complete(request,
  683. buf,
  684. nbytes_sent,
  685. fail,
  686. GLOBUS_FALSE);
  687. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  688. return;
  689. }
  690. }
  691. /* globus_l_gass_transfer_http_writev_callback() */
  692. /*
  693. * Function: globus_l_gass_transfer_http_read_callack()
  694. *
  695. * Description: Callback when the read of from the connection to the active
  696. * buffer has completed or failed.
  697. *
  698. * Parameters:
  699. *
  700. * Returns:
  701. */
  702. static
  703. void
  704. globus_l_gass_transfer_http_read_callback(
  705. void * callback_arg,
  706. globus_io_handle_t * handle,
  707. globus_result_t result,
  708. globus_byte_t * buf,
  709. globus_size_t nbytes)
  710. {
  711. globus_object_t * err = GLOBUS_NULL;
  712. globus_gass_transfer_http_request_proto_t * proto;
  713. globus_gass_transfer_request_t request;
  714. globus_bool_t last_data = GLOBUS_FALSE;
  715. globus_bool_t failure = GLOBUS_FALSE;
  716. globus_size_t offset = 0;
  717. MYNAME(globus_l_gass_transfer_http_read_callback);
  718. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  719. proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
  720. if(result != GLOBUS_SUCCESS)
  721. {
  722. char * tmpstr;
  723. err = globus_error_get(result);
  724. tmpstr = globus_object_printable_to_string(err);
  725. debug_printf(5, (_GTSL("%s(): Error: %s\n"), myname, tmpstr));
  726. globus_libc_free(tmpstr);
  727. }
  728. globus_l_gass_transfer_http_lock();
  729. proto->user_offset += nbytes;
  730. proto->handled += nbytes;
  731. if(nbytes > proto->user_waitlen)
  732. {
  733. proto->user_waitlen = 0;
  734. }
  735. else
  736. {
  737. proto->user_waitlen -= nbytes;
  738. }
  739. if(proto->chunked)
  740. {
  741. proto->chunk_left -= nbytes;
  742. }
  743. if(result != GLOBUS_SUCCESS &&
  744. globus_io_eof(err))
  745. {
  746. proto->eof_read = GLOBUS_TRUE;
  747. }
  748. else if(result != GLOBUS_SUCCESS ||
  749. proto->failure_occurred ||
  750. proto->parse_error)
  751. {
  752. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  753. }
  754. if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF &&
  755. proto->eof_read == GLOBUS_TRUE)
  756. {
  757. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  758. }
  759. else if(proto->recv_state ==
  760. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
  761. proto->handled == proto->length)
  762. {
  763. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  764. }
  765. else if(proto->recv_state ==
  766. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
  767. proto->eof_read == GLOBUS_TRUE &&
  768. proto->handled < proto->length)
  769. {
  770. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  771. }
  772. else if(nbytes==0 && proto->eof_read)
  773. {
  774. proto->failure_occurred = GLOBUS_TRUE;
  775. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  776. }
  777. if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  778. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
  779. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF)
  780. {
  781. char * response;
  782. globus_size_t response_len=0;
  783. globus_size_t offset;
  784. response_len += 1;
  785. response_len += strlen(GLOBUS_L_GENERIC_RESPONSE);
  786. response_len += 3;
  787. response_len += strlen(GLOBUS_L_OK);
  788. response_len += 2;
  789. response = globus_malloc(response_len);
  790. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
  791. offset = sprintf(response,
  792. GLOBUS_L_GENERIC_RESPONSE,
  793. 0,
  794. 200,
  795. GLOBUS_L_OK);
  796. offset += sprintf(response + offset,
  797. CRLF);
  798. debug_printf(4,(_GTSL("%s(): Registering write\n"),myname));
  799. globus_io_register_write(&proto->handle,
  800. (globus_byte_t *) response,
  801. strlen(response),
  802. globus_l_gass_transfer_http_write_response,
  803. proto);
  804. }
  805. /* Register the socket for closing if we're done reading from it */
  806. else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  807. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  808. {
  809. failure = proto->failure_occurred;
  810. buf = proto->user_buffer;
  811. offset = proto->user_offset;
  812. request = proto->request;
  813. last_data = GLOBUS_TRUE;
  814. if(proto->state != GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING)
  815. {
  816. result = globus_l_gass_transfer_http_register_close(proto);
  817. if (result != GLOBUS_SUCCESS)
  818. {
  819. globus_l_gass_transfer_http_close(proto);
  820. }
  821. }
  822. globus_l_gass_transfer_http_unlock();
  823. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
  824. globus_gass_transfer_proto_receive_complete(request,
  825. buf,
  826. offset,
  827. failure,
  828. last_data);
  829. goto out;
  830. }
  831. if(proto->user_waitlen == 0 ||
  832. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  833. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  834. {
  835. /*
  836. * Received the required minimum of data from connection, an
  837. * error, or the end-of file, signal this to GASS
  838. */
  839. if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
  840. {
  841. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  842. }
  843. if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  844. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  845. {
  846. last_data = GLOBUS_TRUE;
  847. }
  848. failure = proto->failure_occurred;
  849. buf = proto->user_buffer;
  850. offset = proto->user_offset;
  851. request = proto->request;
  852. globus_l_gass_transfer_http_unlock();
  853. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
  854. globus_gass_transfer_proto_receive_complete(request,
  855. buf,
  856. offset,
  857. failure,
  858. last_data);
  859. }
  860. else
  861. {
  862. result = globus_l_gass_transfer_http_register_read(proto);
  863. globus_l_gass_transfer_http_unlock();
  864. }
  865. out:
  866. if(err)
  867. {
  868. globus_object_free(err);
  869. }
  870. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  871. return;
  872. }
  873. /* globus_l_gass_transfer_http_read_callback() */
  874. /*
  875. * Function: globus_l_gass_transfer_http_read_buffered_callack()
  876. *
  877. * Description: Callback when the read of from the http to the
  878. * response buffer has completed or failed.
  879. *
  880. * Parameters:
  881. *
  882. * Returns:
  883. */
  884. static
  885. void
  886. globus_l_gass_transfer_http_read_buffered_callback(
  887. void * callback_arg,
  888. globus_io_handle_t * handle,
  889. globus_result_t result,
  890. globus_byte_t * buf,
  891. globus_size_t nbytes)
  892. {
  893. globus_object_t * err = GLOBUS_NULL;
  894. globus_gass_transfer_http_request_proto_t * proto;
  895. MYNAME(globus_l_gass_transfer_http_read_buffered_callback);
  896. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  897. proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
  898. if(result != GLOBUS_SUCCESS)
  899. {
  900. char * tmpstr;
  901. err = globus_error_get(result);
  902. tmpstr = globus_object_printable_to_string(err);
  903. debug_printf(5, (_GTSL("%s(): %s\n"), myname, tmpstr));
  904. globus_libc_free(tmpstr);
  905. }
  906. globus_l_gass_transfer_http_lock();
  907. proto->response_offset += nbytes;
  908. if(result != GLOBUS_SUCCESS &&
  909. globus_io_eof(err))
  910. {
  911. proto->eof_read = GLOBUS_TRUE;
  912. }
  913. else if(result != GLOBUS_SUCCESS)
  914. {
  915. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  916. }
  917. /*
  918. * Copy the document from the response buffer to the user-supplied
  919. * buffer, translating end-of-line if necessary, and handling any
  920. * chunk header/footer information
  921. */
  922. globus_l_gass_transfer_http_handle_chunk(proto);
  923. if(proto->failure_occurred)
  924. {
  925. proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  926. }
  927. /* successful read for server, send response */
  928. if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  929. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
  930. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF &&
  931. proto->recv_state != GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  932. {
  933. char * response;
  934. globus_size_t response_len=0;
  935. globus_size_t offset;
  936. response_len += 1;
  937. response_len += strlen(GLOBUS_L_GENERIC_RESPONSE);
  938. response_len += 3;
  939. response_len += strlen(GLOBUS_L_OK);
  940. response_len += 2;
  941. response = globus_malloc(response_len);
  942. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
  943. offset = sprintf(response,
  944. GLOBUS_L_GENERIC_RESPONSE,
  945. 0,
  946. 200,
  947. GLOBUS_L_OK);
  948. offset += sprintf(response + offset,
  949. CRLF);
  950. debug_printf(4,(_GTSL("%s(): Registering write\n"),myname));
  951. globus_io_register_write(&proto->handle,
  952. (globus_byte_t *) response,
  953. strlen(response),
  954. globus_l_gass_transfer_http_write_response,
  955. proto);
  956. }
  957. /* Register the socket for closing if we're done reading from it */
  958. else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  959. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  960. {
  961. if(proto->state != GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING)
  962. {
  963. result = globus_l_gass_transfer_http_register_close(proto);
  964. if (result != GLOBUS_SUCCESS)
  965. {
  966. globus_l_gass_transfer_http_close(proto);
  967. }
  968. }
  969. }
  970. if(proto->user_waitlen == 0 ||
  971. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  972. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  973. {
  974. globus_gass_transfer_request_t request;
  975. globus_bool_t last_data = GLOBUS_FALSE;
  976. globus_bool_t failure ;
  977. globus_byte_t * buf;
  978. globus_size_t offset;
  979. /*
  980. * Received the required minimum of data from connection, an
  981. * error, or the end-of file, signal this to GASS
  982. */
  983. if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
  984. {
  985. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  986. }
  987. if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
  988. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
  989. {
  990. last_data = GLOBUS_TRUE;
  991. }
  992. if(err)
  993. {
  994. globus_object_free(err);
  995. err = GLOBUS_NULL;
  996. }
  997. proto->oneshot_active = GLOBUS_FALSE;
  998. failure = proto->failure_occurred;
  999. buf = proto->user_buffer;
  1000. offset = proto->user_offset;
  1001. request = proto->request;
  1002. globus_l_gass_transfer_http_signal();
  1003. globus_l_gass_transfer_http_unlock();
  1004. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()\n")));
  1005. globus_gass_transfer_proto_receive_complete(request,
  1006. buf,
  1007. offset,
  1008. failure,
  1009. last_data);
  1010. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  1011. return;
  1012. }
  1013. else
  1014. {
  1015. result = globus_l_gass_transfer_http_register_read(proto);
  1016. }
  1017. if(result != GLOBUS_SUCCESS)
  1018. {
  1019. goto error_exit;
  1020. }
  1021. proto->oneshot_active = GLOBUS_FALSE;
  1022. globus_l_gass_transfer_http_unlock();
  1023. if(err)
  1024. {
  1025. globus_object_free(err);
  1026. }
  1027. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  1028. return;
  1029. error_exit:
  1030. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
  1031. proto->failure_occurred = GLOBUS_TRUE;
  1032. proto->oneshot_active = GLOBUS_FALSE;
  1033. proto->oneshot_active = GLOBUS_FALSE;
  1034. result = globus_l_gass_transfer_http_register_close(proto);
  1035. if(err)
  1036. {
  1037. globus_object_free(err);
  1038. }
  1039. {
  1040. globus_gass_transfer_request_t request;
  1041. globus_byte_t *buf;
  1042. globus_size_t offset;
  1043. request = proto->request;
  1044. buf = proto->user_buffer;
  1045. offset = proto->user_offset;
  1046. /* register close failed, act as though it was closed */
  1047. if (result != GLOBUS_SUCCESS)
  1048. {
  1049. globus_l_gass_transfer_http_close(proto);
  1050. }
  1051. globus_l_gass_transfer_http_unlock();
  1052. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
  1053. globus_gass_transfer_proto_receive_complete(request,
  1054. buf,
  1055. offset,
  1056. GLOBUS_TRUE,
  1057. GLOBUS_TRUE);
  1058. }
  1059. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  1060. return;
  1061. }
  1062. /* globus_l_gass_transfer_http_read_buffered_callback() */
  1063. /*
  1064. * Function: globus_l_gass_transfer_http_close_callback()
  1065. *
  1066. * Description: Called upon completion of close()ing the file handle,
  1067. * Will free the proto instance if the client has called
  1068. * the "done" function
  1069. *
  1070. *
  1071. * Parameters:
  1072. *
  1073. * Returns:
  1074. */
  1075. static
  1076. void
  1077. globus_l_gass_transfer_http_close_callback(
  1078. void * callback_arg,
  1079. globus_io_handle_t * handle,
  1080. globus_result_t result)
  1081. {
  1082. globus_gass_transfer_http_request_proto_t * proto;
  1083. MYNAME(globus_l_gass_transfer_http_close_callback);
  1084. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  1085. proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
  1086. globus_l_gass_transfer_http_lock();
  1087. globus_l_gass_transfer_http_close(proto);
  1088. globus_l_gass_transfer_http_unlock();
  1089. }
  1090. /* globus_l_gass_transfer_http_close_callback() */
  1091. /*
  1092. * Function: globus_l_gass_transfer_http_close()
  1093. *
  1094. * Description: must be called with the mutex locked
  1095. *
  1096. *
  1097. * Parameters:
  1098. *
  1099. * Returns:
  1100. */
  1101. static
  1102. void
  1103. globus_l_gass_transfer_http_close(
  1104. globus_gass_transfer_http_request_proto_t * proto)
  1105. {
  1106. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE;
  1107. if(proto->destroy_called)
  1108. {
  1109. globus_l_gass_transfer_http_proto_destroy(proto);
  1110. }
  1111. globus_l_gass_transfer_http_closing--;
  1112. globus_l_gass_transfer_http_signal();
  1113. }
  1114. /* globus_l_gass_transfer_http_close() */
  1115. /*
  1116. * Function: globus_l_gass_transfer_http_register_close()
  1117. *
  1118. * Description: must be called with the mutex locked
  1119. *
  1120. *
  1121. * Parameters:
  1122. *
  1123. * Returns:
  1124. */
  1125. static
  1126. globus_result_t
  1127. globus_l_gass_transfer_http_register_close(
  1128. globus_gass_transfer_http_request_proto_t * proto)
  1129. {
  1130. globus_result_t result;
  1131. MYNAME(globus_l_gass_transfer_http_register_close);
  1132. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
  1133. globus_l_gass_transfer_http_closing++;
  1134. debug_printf(4,(_GTSL("%s(): registering close on %p\n"), myname, &proto->handle));
  1135. result = globus_io_register_close(
  1136. &proto->handle,
  1137. globus_l_gass_transfer_http_close_callback,
  1138. proto);
  1139. return result;
  1140. }
  1141. /* globus_l_gass_transfer_http_register_close() */
  1142. /*
  1143. * Function: globus_l_gass_transfer_http_listener_close_callback()
  1144. *
  1145. * Description:
  1146. *
  1147. * Parameters:
  1148. *
  1149. * Returns:
  1150. */
  1151. static
  1152. void
  1153. globus_l_gass_transfer_http_listener_close_callback(
  1154. void * callback_arg,
  1155. globus_io_handle_t * handle,
  1156. globus_result_t result)
  1157. {
  1158. globus_gass_transfer_http_listener_proto_t *
  1159. proto;
  1160. MYNAME(globus_l_gass_transfer_http_listener_close_callback);
  1161. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  1162. proto = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
  1163. globus_l_gass_transfer_http_lock();
  1164. globus_l_gass_transfer_http_listener_close(proto);
  1165. globus_l_gass_transfer_http_unlock();
  1166. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  1167. }
  1168. /* globus_l_gass_transfer_http_listener_close_callback() */
  1169. /*
  1170. * Function: globus_l_gass_transfer_http_listener_close()
  1171. *
  1172. * Description: must be called with the mutex locked
  1173. *
  1174. * Parameters:
  1175. *
  1176. * Returns:
  1177. */
  1178. static
  1179. void
  1180. globus_l_gass_transfer_http_listener_close(
  1181. globus_gass_transfer_http_listener_proto_t * proto)
  1182. {
  1183. proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED;
  1184. if(proto->destroy_called)
  1185. {
  1186. globus_l_gass_transfer_http_listener_proto_destroy(proto);
  1187. }
  1188. globus_l_gass_transfer_http_closing--;
  1189. globus_l_gass_transfer_http_signal();
  1190. }
  1191. /* globus_l_gass_transfer_http_listener_close() */
  1192. static
  1193. void
  1194. globus_l_gass_transfer_http_register_listener_close(
  1195. globus_gass_transfer_http_listener_proto_t * proto)
  1196. {
  1197. globus_result_t result;
  1198. MYNAME(globus_l_gass_transfer_http_register_listener_close);
  1199. globus_l_gass_transfer_http_closing++;
  1200. debug_printf(4,(_GTSL("%s(): registering close on %p\n"), myname, &proto->handle));
  1201. result = globus_io_register_close(
  1202. &proto->handle,
  1203. globus_l_gass_transfer_http_listener_close_callback,
  1204. proto);
  1205. globus_assert(result == GLOBUS_SUCCESS);
  1206. if(result != GLOBUS_SUCCESS)
  1207. {
  1208. globus_l_gass_transfer_http_listener_close(proto);
  1209. }
  1210. }
  1211. /* globus_l_gass_transfer_http_register_listener_close() */
  1212. /*
  1213. * Function: globus_l_gass_transfer_http_listener_proto_destroy()
  1214. *
  1215. * Description:
  1216. *
  1217. * Parameters:
  1218. *
  1219. * Returns:
  1220. */
  1221. static
  1222. void
  1223. globus_l_gass_transfer_http_listener_proto_destroy(
  1224. globus_gass_transfer_http_listener_proto_t *
  1225. proto)
  1226. {
  1227. globus_free(proto);
  1228. }
  1229. /* globus_l_gass_transfer_http_listener_proto_destroy() */
  1230. /*
  1231. * Function: globus_l_gass_transfer_http_destroy()
  1232. *
  1233. * Description:
  1234. *
  1235. * Parameters:
  1236. *
  1237. * Returns:
  1238. */
  1239. static
  1240. void
  1241. globus_l_gass_transfer_http_destroy(
  1242. globus_gass_transfer_request_proto_t * proto,
  1243. globus_gass_transfer_request_t request)
  1244. {
  1245. globus_gass_transfer_http_request_proto_t * new_proto;
  1246. MYNAME(globus_l_gass_transfer_http_destroy);
  1247. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  1248. new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
  1249. globus_l_gass_transfer_http_lock();
  1250. if(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING ||
  1251. new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED ||
  1252. new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING ||
  1253. new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED)
  1254. {
  1255. new_proto->destroy_called=GLOBUS_TRUE;
  1256. }
  1257. else if(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE)
  1258. {
  1259. globus_l_gass_transfer_http_proto_destroy(new_proto);
  1260. }
  1261. globus_l_gass_transfer_http_unlock();
  1262. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  1263. }
  1264. /* globus_l_gass_transfer_http_destroy() */
  1265. /*
  1266. * Function: globus_l_gass_transfer_http_listener_destroy()
  1267. *
  1268. * Description:
  1269. *
  1270. * Parameters:
  1271. *
  1272. * Returns:
  1273. */
  1274. static
  1275. void
  1276. globus_l_gass_transfer_http_listener_destroy(
  1277. globus_gass_transfer_listener_proto_t * proto,
  1278. globus_gass_transfer_listener_t listener)
  1279. {
  1280. globus_gass_transfer_http_listener_proto_t *new_proto;
  1281. MYNAME(globus_l_gass_transfer_http_listener_destroy);
  1282. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  1283. new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
  1284. globus_l_gass_transfer_http_lock();
  1285. if(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED)
  1286. {
  1287. new_proto->destroy_called=GLOBUS_TRUE;
  1288. }
  1289. else
  1290. {
  1291. globus_l_gass_transfer_http_listener_proto_destroy(new_proto);
  1292. }
  1293. globus_l_gass_transfer_http_unlock();
  1294. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  1295. }
  1296. /* globus_l_gass_transfer_http_listener_destroy() */
  1297. /*
  1298. * Function: globus_l_gass_transfer_http_listen()
  1299. *
  1300. * Description:
  1301. *
  1302. * Parameters:
  1303. *
  1304. * Returns:
  1305. */
  1306. static
  1307. void
  1308. globus_l_gass_transfer_http_listen(
  1309. globus_gass_transfer_listener_proto_t * proto,
  1310. globus_gass_transfer_listener_t listener)
  1311. {
  1312. globus_gass_transfer_http_listener_proto_t *new_proto;
  1313. globus_result_t result;
  1314. globus_reltime_t delay_time;
  1315. MYNAME(globus_l_gass_transfer_http_listen);
  1316. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  1317. new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
  1318. globus_l_gass_transfer_http_lock();
  1319. debug_printf(4,(_GTSL("%s(): registering listen on %p\n"),
  1320. myname,
  1321. &new_proto->handle));
  1322. result = globus_io_tcp_register_listen(
  1323. &new_proto->handle,
  1324. globus_l_gass_transfer_http_listen_callback,
  1325. (void *) new_proto);
  1326. if(result != GLOBUS_SUCCESS)
  1327. {
  1328. GlobusTimeReltimeSet(delay_time, 0, 0);
  1329. debug_printf(4,(_GTSL("%s(): registering oneshot because listen failed\n"),
  1330. myname));
  1331. globus_callback_register_oneshot(
  1332. GLOBUS_NULL,
  1333. &delay_time,
  1334. globus_l_gass_transfer_http_callback_listen_callback,
  1335. (void *) new_proto);
  1336. }
  1337. else
  1338. {
  1339. new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING;
  1340. }
  1341. globus_l_gass_transfer_http_unlock();
  1342. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  1343. }
  1344. /* globus_l_gass_transfer_http_listen() */
  1345. static
  1346. void
  1347. globus_l_gass_transfer_http_listen_callback(
  1348. void * callback_arg,
  1349. globus_io_handle_t * handle,
  1350. globus_result_t result)
  1351. {
  1352. globus_gass_transfer_http_listener_proto_t *proto;
  1353. globus_gass_transfer_listener_t listener;
  1354. MYNAME(globus_l_gass_transfer_http_listen_callback);
  1355. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  1356. proto = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
  1357. globus_l_gass_transfer_http_lock();
  1358. switch(proto->state)
  1359. {
  1360. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
  1361. proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY;
  1362. break;
  1363. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
  1364. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
  1365. break;
  1366. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
  1367. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
  1368. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
  1369. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
  1370. globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING);
  1371. globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING);
  1372. globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY);
  1373. globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2);
  1374. }
  1375. listener = proto->listener;
  1376. globus_l_gass_transfer_http_unlock();
  1377. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_listener_ready()")));
  1378. globus_gass_transfer_proto_listener_ready(listener);
  1379. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  1380. }
  1381. /* globus_l_gass_transfer_http_listen_callback() */
  1382. static
  1383. void
  1384. globus_l_gass_transfer_http_accept_callback(
  1385. void * callback_arg,
  1386. globus_io_handle_t * handle,
  1387. globus_result_t result)
  1388. {
  1389. globus_gass_transfer_http_listener_proto_t *l;
  1390. MYNAME(globus_l_gass_transfer_http_accept_callback);
  1391. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  1392. globus_l_gass_transfer_http_lock();
  1393. fflush(stdout);
  1394. l = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
  1395. switch(l->state)
  1396. {
  1397. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
  1398. l->request->response_buffer = globus_malloc(GLOBUS_L_GASS_RESPONSE_LEN *
  1399. sizeof(globus_byte_t));
  1400. l->request->response_buflen = GLOBUS_L_GASS_RESPONSE_LEN;
  1401. l->request->response_offset = 0;
  1402. l->request->parsed_offset = 0;
  1403. if(result != GLOBUS_SUCCESS)
  1404. {
  1405. globus_l_gass_transfer_http_unlock();
  1406. globus_l_gass_transfer_http_request_callback(
  1407. l,
  1408. &l->request->handle,
  1409. result,
  1410. l->request->response_buffer,
  1411. 0);
  1412. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_accept_callback()\n")));
  1413. return;
  1414. }
  1415. else
  1416. {
  1417. debug_printf(4, (_GTSL("%s(): Registering read on %p\n"),
  1418. myname,
  1419. &l->request->handle));
  1420. globus_io_register_read(&l->request->handle,
  1421. l->request->response_buffer,
  1422. l->request->response_buflen,
  1423. 1,
  1424. globus_l_gass_transfer_http_request_callback,
  1425. l);
  1426. }
  1427. break;
  1428. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
  1429. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
  1430. globus_l_gass_transfer_http_unlock();
  1431. globus_gass_transfer_proto_new_listener_request(l->listener,
  1432. l->request->request,
  1433. GLOBUS_NULL);
  1434. globus_l_gass_transfer_http_lock();
  1435. /* should destroy the proto->request here? */
  1436. break;
  1437. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
  1438. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
  1439. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
  1440. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
  1441. globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING);
  1442. globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING);
  1443. globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY);
  1444. globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1);
  1445. }
  1446. globus_l_gass_transfer_http_unlock();
  1447. debug_printf(3, (_GTSL("Exiting %s()\n"), myname));
  1448. }
  1449. /* globus_l_gass_transfer_http_accept_callback() */
  1450. static
  1451. void
  1452. globus_l_gass_transfer_http_request_refer(
  1453. globus_gass_transfer_request_proto_t * rproto,
  1454. globus_gass_transfer_request_t request)
  1455. {
  1456. globus_gass_transfer_http_request_proto_t * proto;
  1457. globus_gass_transfer_referral_t referral;
  1458. int rc;
  1459. char * referral_string;
  1460. globus_size_t referral_count;
  1461. globus_size_t body_count=0; /* :) */
  1462. globus_size_t offset;
  1463. globus_size_t x;
  1464. globus_size_t i;
  1465. globus_size_t digits = 0;
  1466. MYNAME(globus_l_gass_transfer_http_request_refer);
  1467. globus_l_gass_transfer_http_lock();
  1468. proto = (globus_gass_transfer_http_request_proto_t *) rproto;
  1469. rc = globus_gass_transfer_request_get_referral(request,
  1470. &referral);
  1471. /* HTTP/1.1 302 Document Moved CRLF
  1472. * Location: referral.url[0] CRLF
  1473. * Content-Length: $body_count CRLF
  1474. * Content-Type: text/html CRLF
  1475. * CRLF
  1476. * <html><head><title>300 Multiple Choices</title></head><body>
  1477. * <a href="<referral.url[1]>">referral.url[1]</a><br>
  1478. * ..
  1479. * <a href="<referral.url[i]>">referral.url[i]</a><br>
  1480. * </body></html>
  1481. */
  1482. referral_count = 1;
  1483. referral_count += strlen(GLOBUS_L_REFER_RESPONSE);
  1484. referral_count += strlen(GLOBUS_L_LOCATION_HEADER);
  1485. referral_count += 2;
  1486. referral_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
  1487. referral_count += strlen(GLOBUS_L_HTML_HEADER);
  1488. referral_count += strlen(referral.url[0]);
  1489. body_count += strlen(GLOBUS_L_HTML_REFERRAL_BODY_HEAD);
  1490. body_count += strlen(GLOBUS_L_HTML_REFERRAL_BODY_TAIL);
  1491. for(i = 0 ; i < referral.count; i++)
  1492. {
  1493. body_count += strlen(GLOBUS_L_HTML_HREF);
  1494. body_count += strlen(referral.url[i]);
  1495. body_count += strlen(referral.url[i]);
  1496. }
  1497. /* count the number of decimal digits in the body */
  1498. x=body_count;
  1499. do
  1500. {
  1501. digits++;
  1502. x /= 10;
  1503. } while(x > 0);
  1504. referral_count += digits;
  1505. referral_string = globus_malloc(referral_count + body_count);
  1506. offset = sprintf(referral_string,
  1507. GLOBUS_L_REFER_RESPONSE);
  1508. offset += sprintf(referral_string + offset,
  1509. GLOBUS_L_LOCATION_HEADER,
  1510. referral.url[0]);
  1511. offset += sprintf(referral_string + offset,
  1512. GLOBUS_L_HTML_HEADER);
  1513. offset += sprintf(referral_string + offset,
  1514. GLOBUS_L_CONTENT_LENGTH_HEADER,
  1515. (long) body_count);
  1516. offset += sprintf(referral_string + offset,
  1517. CRLF);
  1518. offset += sprintf(referral_string + offset,
  1519. GLOBUS_L_HTML_REFERRAL_BODY_HEAD);
  1520. for(i = 0 ; i < referral.count; i++)
  1521. {
  1522. offset += sprintf(referral_string + offset,
  1523. GLOBUS_L_HTML_HREF,
  1524. referral.url[i],
  1525. referral.url[i]);
  1526. }
  1527. offset += sprintf(referral_string + offset,
  1528. GLOBUS_L_HTML_REFERRAL_BODY_TAIL);
  1529. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED;
  1530. globus_gass_transfer_referral_destroy(&referral);
  1531. debug_printf(4, (_GTSL("%s(): Registering write on %p\n"),
  1532. myname,
  1533. &proto->handle));
  1534. globus_io_register_write(&proto->handle,
  1535. (globus_byte_t *) referral_string,
  1536. strlen(referral_string),
  1537. globus_l_gass_transfer_http_write_response,
  1538. proto);
  1539. globus_l_gass_transfer_http_unlock();
  1540. }
  1541. /* globus_l_gass_transfer_http_request_refer() */
  1542. static
  1543. void
  1544. globus_l_gass_transfer_http_request_deny(
  1545. globus_gass_transfer_request_proto_t * rproto,
  1546. globus_gass_transfer_request_t request)
  1547. {
  1548. globus_gass_transfer_http_request_proto_t * proto;
  1549. char * deny_string;
  1550. globus_size_t deny_count;
  1551. globus_size_t body_count=0; /* :) */
  1552. globus_size_t offset;
  1553. globus_size_t x;
  1554. globus_size_t digits = 0;
  1555. int reason;
  1556. char * message;
  1557. MYNAME(globus_l_gass_transfer_http_request_deny);
  1558. globus_l_gass_transfer_http_lock();
  1559. proto = (globus_gass_transfer_http_request_proto_t *) rproto;
  1560. reason = globus_gass_transfer_request_get_denial_reason(request);
  1561. if(reason < 400 ||
  1562. reason >= 600)
  1563. {
  1564. reason = 500;
  1565. message = globus_libc_strdup(GLOBUS_L_DEFAULT_DENIAL_MESSAGE);
  1566. }
  1567. else
  1568. {
  1569. message = globus_gass_transfer_request_get_denial_message(request);
  1570. if(message == GLOBUS_NULL)
  1571. {
  1572. message = globus_libc_strdup(GLOBUS_L_DEFAULT_DENIAL_MESSAGE);
  1573. }
  1574. }
  1575. /* HTTP/1.1 %d %s CRLF
  1576. * Content-Length: $body_count CRLF
  1577. * Content-Type: text/html CRLF
  1578. * CRLF
  1579. * <html><head><title>%d %s</title></head><body> CRLF
  1580. * %d %s</title></body></html> CRLF
  1581. */
  1582. deny_count = 1;
  1583. deny_count += strlen(GLOBUS_L_DENIAL_RESPONSE);
  1584. deny_count += 3 ; /* code */
  1585. deny_count += strlen(message);
  1586. deny_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
  1587. deny_count += strlen(GLOBUS_L_HTML_HEADER);
  1588. deny_count += 2;
  1589. body_count += strlen(GLOBUS_L_HTML_DENIAL_BODY);
  1590. body_count += (strlen(message) * 3);
  1591. body_count += (3 * 3); /* code */
  1592. /* count the number of decimal digits in the body */
  1593. x=body_count;
  1594. do
  1595. {
  1596. digits++;
  1597. x /= 10;
  1598. } while(x > 0);
  1599. deny_count += digits;
  1600. deny_string = globus_malloc(deny_count + body_count);
  1601. offset = sprintf(deny_string,
  1602. GLOBUS_L_DENIAL_RESPONSE,
  1603. reason,
  1604. message);
  1605. offset += sprintf(deny_string + offset,
  1606. GLOBUS_L_HTML_HEADER);
  1607. offset += sprintf(deny_string + offset,
  1608. GLOBUS_L_CONTENT_LENGTH_HEADER,
  1609. (long) body_count);
  1610. offset += sprintf(deny_string + offset,
  1611. CRLF);
  1612. offset += sprintf(deny_string + offset,
  1613. GLOBUS_L_HTML_DENIAL_BODY,
  1614. reason,
  1615. message,
  1616. reason,
  1617. message);
  1618. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED;
  1619. globus_free(message);
  1620. debug_printf(4, (_GTSL("%s(): Registering write on %p\n"),
  1621. myname,
  1622. &proto->handle));
  1623. globus_io_register_write(&proto->handle,
  1624. (globus_byte_t *) deny_string,
  1625. strlen(deny_string),
  1626. globus_l_gass_transfer_http_write_response,
  1627. proto);
  1628. globus_l_gass_transfer_http_unlock();
  1629. }
  1630. /* globus_l_gass_transfer_http_request_deny() */
  1631. static
  1632. void
  1633. globus_l_gass_transfer_http_request_authorize(
  1634. globus_gass_transfer_request_proto_t * rproto,
  1635. globus_gass_transfer_request_t request)
  1636. {
  1637. globus_gass_transfer_http_request_proto_t * proto;
  1638. char * authorize_string;
  1639. globus_size_t authorize_count=0;
  1640. globus_size_t offset;
  1641. globus_size_t length;
  1642. globus_reltime_t delay_time;
  1643. MYNAME(globus_l_gass_transfer_http_request_authorize);
  1644. globus_l_gass_transfer_http_lock();
  1645. proto = (globus_gass_transfer_http_request_proto_t *) rproto;
  1646. switch(proto->type)
  1647. {
  1648. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
  1649. /* Let's always send an HTTP/1.0 response, to make things easier */
  1650. length = globus_gass_transfer_request_get_length(proto->request);
  1651. if(length != 0)
  1652. {
  1653. globus_size_t x = length;
  1654. globus_size_t digits = 0;
  1655. /* count the number of decimal digits in length */
  1656. do
  1657. {
  1658. digits++;
  1659. x /= 10;
  1660. } while(x > 0);
  1661. /* Send a content-length field */
  1662. authorize_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
  1663. authorize_count += digits;
  1664. }
  1665. authorize_count += 1;
  1666. authorize_count += strlen(GLOBUS_L_GENERIC_RESPONSE);
  1667. authorize_count += 3;
  1668. authorize_count += strlen(GLOBUS_L_OK);
  1669. authorize_count += 2;
  1670. if(proto->text_mode)
  1671. {
  1672. authorize_count += strlen(GLOBUS_L_TEXT_HEADER);
  1673. authorize_string = globus_malloc(authorize_count);
  1674. offset = sprintf(authorize_string,
  1675. GLOBUS_L_GENERIC_RESPONSE,
  1676. 0,
  1677. 200,
  1678. GLOBUS_L_OK);
  1679. offset += sprintf(authorize_string + offset,
  1680. GLOBUS_L_TEXT_HEADER);
  1681. }
  1682. else
  1683. {
  1684. authorize_count += strlen(GLOBUS_L_BINARY_HEADER);
  1685. authorize_string = globus_malloc(authorize_count);
  1686. offset = sprintf(authorize_string,
  1687. GLOBUS_L_GENERIC_RESPONSE,
  1688. 0,
  1689. 200,
  1690. GLOBUS_L_OK);
  1691. offset += sprintf(authorize_string + offset,
  1692. GLOBUS_L_BINARY_HEADER);
  1693. }
  1694. if(length != 0)
  1695. {
  1696. offset += sprintf(authorize_string + offset,
  1697. GLOBUS_L_CONTENT_LENGTH_HEADER,
  1698. (long) length);
  1699. }
  1700. offset += sprintf(authorize_string + offset,
  1701. CRLF);
  1702. break;
  1703. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
  1704. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
  1705. /* send nothing back yet */
  1706. break;
  1707. default:
  1708. globus_assert(GLOBUS_FALSE);
  1709. }
  1710. if(authorize_count != 0)
  1711. {
  1712. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
  1713. debug_printf(4, (_GTSL("%s(): registering write on %p\n"),
  1714. myname,
  1715. &proto->handle));
  1716. globus_io_register_write(&proto->handle,
  1717. (globus_byte_t *) authorize_string,
  1718. strlen(authorize_string),
  1719. globus_l_gass_transfer_http_write_response,
  1720. proto);
  1721. }
  1722. else
  1723. {
  1724. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  1725. GlobusTimeReltimeSet(delay_time, 0, 0);
  1726. debug_printf(4, (_GTSL("%s(): registering oneshot\n"),
  1727. myname));
  1728. globus_callback_register_oneshot(
  1729. GLOBUS_NULL,
  1730. &delay_time,
  1731. globus_l_gass_transfer_http_callback_ready_callback,
  1732. (void *) proto);
  1733. }
  1734. globus_l_gass_transfer_http_unlock();
  1735. }
  1736. /* globus_l_gass_transfer_http_request_authorize() */
  1737. static
  1738. void
  1739. globus_l_gass_transfer_http_write_response(
  1740. void * arg,
  1741. globus_io_handle_t * handle,
  1742. globus_result_t result,
  1743. globus_byte_t * buf,
  1744. globus_size_t nbytes)
  1745. {
  1746. globus_gass_transfer_http_request_proto_t * proto;
  1747. globus_gass_transfer_request_t request;
  1748. globus_free(buf);
  1749. globus_l_gass_transfer_http_lock();
  1750. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  1751. switch(proto->state)
  1752. {
  1753. case GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING:
  1754. if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET)
  1755. {
  1756. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  1757. globus_l_gass_transfer_http_unlock();
  1758. request = proto->request;
  1759. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
  1760. globus_gass_transfer_proto_request_ready(request,
  1761. (globus_gass_transfer_request_proto_t *) proto);
  1762. return;
  1763. }
  1764. /* other types fall through */
  1765. default:
  1766. result = globus_l_gass_transfer_http_register_close(proto);
  1767. if (result != GLOBUS_SUCCESS)
  1768. {
  1769. globus_l_gass_transfer_http_close(proto);
  1770. }
  1771. globus_l_gass_transfer_http_unlock();
  1772. return;
  1773. }
  1774. }
  1775. /* globus_l_gass_transfer_http_write_response() */
  1776. static
  1777. globus_bool_t
  1778. globus_l_gass_transfer_http_authorization_callback(
  1779. void * arg,
  1780. globus_io_handle_t * handle,
  1781. globus_result_t result,
  1782. char * identity,
  1783. gss_ctx_id_t context_handle)
  1784. {
  1785. globus_gass_transfer_http_listener_proto_t *proto;
  1786. int rc;
  1787. MYNAME(globus_l_gass_transfer_http_authorization_callback);
  1788. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  1789. globus_l_gass_transfer_http_lock();
  1790. proto = (globus_gass_transfer_http_listener_proto_t *) arg;
  1791. proto->request->connected_subject = globus_libc_strdup(identity);
  1792. switch(proto->request->authorization_mode)
  1793. {
  1794. case GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF:
  1795. if(strcmp(identity, globus_l_gass_transfer_http_subject_name) == 0)
  1796. {
  1797. rc = GLOBUS_TRUE;
  1798. goto finish;
  1799. }
  1800. else
  1801. {
  1802. rc = GLOBUS_FALSE;
  1803. goto finish;
  1804. }
  1805. case GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST:
  1806. rc = GLOBUS_FALSE;
  1807. goto finish;
  1808. case GLOBUS_GASS_TRANSFER_AUTHORIZE_SUBJECT:
  1809. if(strcmp(identity, proto->request->authorized_subject) == 0)
  1810. {
  1811. rc = GLOBUS_TRUE;
  1812. goto finish;
  1813. }
  1814. else
  1815. {
  1816. rc = GLOBUS_FALSE;
  1817. goto finish;
  1818. }
  1819. case GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK:
  1820. rc = GLOBUS_TRUE;
  1821. goto finish;
  1822. }
  1823. finish:
  1824. globus_l_gass_transfer_http_unlock();
  1825. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_authorization_callback()\n")));
  1826. return rc;
  1827. }
  1828. /* globus_l_gass_transfer_http_authorization_callback() */
  1829. static
  1830. void
  1831. globus_l_gass_transfer_http_proto_destroy(
  1832. globus_gass_transfer_http_request_proto_t * proto)
  1833. {
  1834. if(proto->response_buffer != GLOBUS_NULL)
  1835. {
  1836. globus_free(proto->response_buffer);
  1837. }
  1838. if(proto->reason != GLOBUS_NULL)
  1839. {
  1840. globus_free(proto->reason);
  1841. }
  1842. if(proto->connected_subject != GLOBUS_NULL)
  1843. {
  1844. globus_free(proto->connected_subject);
  1845. }
  1846. if(proto->client_side)
  1847. {
  1848. globus_url_destroy(&proto->url);
  1849. }
  1850. else
  1851. {
  1852. if(proto->method)
  1853. {
  1854. globus_free(proto->method);
  1855. }
  1856. if(proto->uri)
  1857. {
  1858. globus_free(proto->uri);
  1859. }
  1860. }
  1861. globus_i_gass_transfer_keyvalue_destroy(
  1862. &proto->headers);
  1863. globus_free(proto);
  1864. }
  1865. /* globus_l_gass_transfer_http_proto_destroy() */
  1866. /*
  1867. * Function: globus_l_gass_transfer_http_new_request(()
  1868. *
  1869. * Description: Create a new request's "proto" structure
  1870. *
  1871. * Parameters:
  1872. *
  1873. * Returns:
  1874. */
  1875. static
  1876. void
  1877. globus_l_gass_transfer_http_new_request(
  1878. globus_gass_transfer_request_t request,
  1879. globus_gass_transfer_requestattr_t * attr)
  1880. {
  1881. int rc=GLOBUS_SUCCESS;
  1882. char * proxy=GLOBUS_NULL;
  1883. globus_gass_transfer_file_mode_t file_mode=GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY;
  1884. globus_io_attr_t tcp_attr;
  1885. globus_result_t result;
  1886. globus_gass_transfer_http_request_proto_t * proto;
  1887. int sndbuf;
  1888. int rcvbuf;
  1889. int nodelay;
  1890. globus_reltime_t delay_time;
  1891. MYNAME(globus_l_gass_transfer_http_new_request);
  1892. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  1893. switch(globus_gass_transfer_request_get_type(request))
  1894. {
  1895. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
  1896. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
  1897. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
  1898. break;
  1899. default:
  1900. goto error_exit;
  1901. }
  1902. /* Allocate proto instance */
  1903. proto = (globus_gass_transfer_http_request_proto_t *)
  1904. globus_malloc(sizeof(globus_gass_transfer_http_request_proto_t));
  1905. if(proto == GLOBUS_NULL)
  1906. {
  1907. goto error_exit;
  1908. }
  1909. result = globus_io_tcpattr_init(&tcp_attr);
  1910. if(result != GLOBUS_SUCCESS)
  1911. {
  1912. goto proto_error;
  1913. }
  1914. globus_io_attr_set_socket_keepalive(&tcp_attr, GLOBUS_TRUE);
  1915. if(*attr != GLOBUS_NULL)
  1916. {
  1917. /* Check attributes we care about */
  1918. globus_gass_transfer_requestattr_get_proxy_url(attr,
  1919. &proxy);
  1920. rc = globus_gass_transfer_requestattr_get_socket_sndbuf(
  1921. attr,
  1922. &sndbuf);
  1923. if(rc != GLOBUS_SUCCESS)
  1924. {
  1925. goto tcpattr_error;
  1926. }
  1927. else
  1928. {
  1929. if(sndbuf != 0)
  1930. {
  1931. globus_io_attr_set_socket_sndbuf(&tcp_attr,
  1932. sndbuf);
  1933. }
  1934. }
  1935. rc = globus_gass_transfer_requestattr_get_socket_rcvbuf(
  1936. attr,
  1937. &rcvbuf);
  1938. if(rc != GLOBUS_SUCCESS)
  1939. {
  1940. goto tcpattr_error;
  1941. }
  1942. else
  1943. {
  1944. if(rcvbuf != 0)
  1945. {
  1946. globus_io_attr_set_socket_rcvbuf(&tcp_attr,
  1947. rcvbuf);
  1948. }
  1949. }
  1950. rc = globus_gass_transfer_requestattr_get_socket_nodelay(
  1951. attr,
  1952. &nodelay);
  1953. if(rc != GLOBUS_SUCCESS)
  1954. {
  1955. goto tcpattr_error;
  1956. }
  1957. else
  1958. {
  1959. globus_io_attr_set_tcp_nodelay(&tcp_attr,
  1960. nodelay);
  1961. }
  1962. /* File mode is important on Windows */
  1963. rc = globus_gass_transfer_requestattr_get_file_mode(attr,
  1964. &file_mode);
  1965. if(rc != GLOBUS_SUCCESS)
  1966. {
  1967. goto tcpattr_error;
  1968. }
  1969. rc = globus_gass_transfer_requestattr_get_block_size(attr,
  1970. &proto->block_size);
  1971. if(rc != GLOBUS_SUCCESS)
  1972. {
  1973. goto tcpattr_error;
  1974. }
  1975. }
  1976. /* Verify URL */
  1977. if(proxy)
  1978. {
  1979. rc = globus_url_parse(proxy,
  1980. &proto->proxy_url);
  1981. if(rc != GLOBUS_SUCCESS)
  1982. {
  1983. goto tcpattr_error;
  1984. }
  1985. if(strcmp(proto->proxy_url.scheme, "http") != 0 &&
  1986. strcmp(proto->proxy_url.scheme, "https") != 0)
  1987. {
  1988. goto proxy_error;
  1989. }
  1990. }
  1991. proto->url_string = globus_gass_transfer_request_get_url(request);
  1992. rc = globus_url_parse(proto->url_string,
  1993. &proto->url);
  1994. if(rc != GLOBUS_SUCCESS)
  1995. {
  1996. goto proxy_error;
  1997. }
  1998. if(proto->url.url_path == GLOBUS_NULL)
  1999. {
  2000. proto->url.url_path = globus_libc_strdup("/");
  2001. }
  2002. if(strcmp(proto->url.scheme, "http") != 0 &&
  2003. strcmp(proto->url.scheme, "https") != 0)
  2004. {
  2005. goto url_error;
  2006. }
  2007. /* If https, set security attributes of TCP handle */
  2008. if(strcmp(proto->url.scheme, "https")== 0)
  2009. {
  2010. globus_io_secure_authorization_data_t data;
  2011. globus_gass_transfer_authorization_t mode;
  2012. char * subject;
  2013. globus_result_t result;
  2014. globus_io_secure_authorization_data_initialize(&data);
  2015. result = globus_io_attr_set_secure_authentication_mode(
  2016. &tcp_attr,
  2017. GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
  2018. GLOBUS_NULL);
  2019. if(result != GLOBUS_SUCCESS)
  2020. {
  2021. goto url_error;
  2022. }
  2023. result = globus_io_attr_set_secure_channel_mode(
  2024. &tcp_attr,
  2025. GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
  2026. if(result != GLOBUS_SUCCESS)
  2027. {
  2028. goto url_error;
  2029. }
  2030. if(*attr != GLOBUS_NULL)
  2031. {
  2032. rc = globus_gass_transfer_secure_requestattr_get_authorization(
  2033. attr,
  2034. &mode,
  2035. &subject);
  2036. if(rc != GLOBUS_SUCCESS)
  2037. {
  2038. goto url_error;
  2039. }
  2040. }
  2041. else
  2042. {
  2043. mode = GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF;
  2044. }
  2045. switch(mode)
  2046. {
  2047. case GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF:
  2048. globus_io_attr_set_secure_authorization_mode(
  2049. &tcp_attr,
  2050. GLOBUS_IO_SECURE_AUTHORIZATION_MODE_SELF,
  2051. GLOBUS_NULL);
  2052. break;
  2053. case GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST:
  2054. subject = globus_malloc(strlen(proto->url.host) +
  2055. strlen("/CN=")
  2056. +1);
  2057. sprintf(subject,
  2058. "/CN=%s",
  2059. proto->url.host);
  2060. globus_io_secure_authorization_data_set_identity(
  2061. &data,
  2062. subject);
  2063. globus_io_attr_set_secure_authorization_mode(
  2064. &tcp_attr,
  2065. GLOBUS_IO_SECURE_AUTHORIZATION_MODE_IDENTITY,
  2066. &data);
  2067. globus_io_secure_authorization_data_destroy(&data);
  2068. globus_free(subject);
  2069. break;
  2070. case GLOBUS_GASS_TRANSFER_AUTHORIZE_SUBJECT:
  2071. globus_io_secure_authorization_data_set_identity(
  2072. &data,
  2073. subject);
  2074. globus_io_attr_set_secure_authorization_mode(
  2075. &tcp_attr,
  2076. GLOBUS_IO_SECURE_AUTHORIZATION_MODE_IDENTITY,
  2077. &data);
  2078. globus_io_secure_authorization_data_destroy(&data);
  2079. break;
  2080. case GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK:
  2081. globus_assert(mode != GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK);
  2082. goto url_error;
  2083. }
  2084. }
  2085. if(proto == GLOBUS_NULL)
  2086. {
  2087. goto url_error;
  2088. }
  2089. /* Initialize the proto instance */
  2090. proto->send_buffer = globus_l_gass_transfer_http_send;
  2091. proto->recv_buffer = globus_l_gass_transfer_http_receive;
  2092. proto->fail = globus_l_gass_transfer_http_fail;
  2093. proto->deny = GLOBUS_NULL;
  2094. proto->refer = GLOBUS_NULL;
  2095. proto->authorize = GLOBUS_NULL;
  2096. proto->destroy = globus_l_gass_transfer_http_destroy;
  2097. proto->text_mode = (file_mode == GLOBUS_GASS_TRANSFER_FILE_MODE_TEXT);
  2098. proto->line_mode = GLOBUS_L_LINE_MODE_UNKNOWN;
  2099. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING;
  2100. proto->request = request;
  2101. proto->type = globus_gass_transfer_request_get_type(request);
  2102. proto->code = 0;
  2103. proto->reason = 0;
  2104. proto->parse_error = GLOBUS_FALSE;
  2105. proto->destroy_called = GLOBUS_FALSE;
  2106. proto->headers = GLOBUS_NULL;
  2107. proto->response_buffer = GLOBUS_NULL;
  2108. proto->length = 0;
  2109. proto->handled = 0;
  2110. proto->chunked = GLOBUS_FALSE;
  2111. proto->chunk_left = 0;
  2112. proto->failure_occurred = GLOBUS_FALSE;
  2113. proto->oneshot_registered = GLOBUS_FALSE;
  2114. proto->oneshot_active = GLOBUS_FALSE;
  2115. proto->eof_read = GLOBUS_FALSE;
  2116. proto->client_side = GLOBUS_TRUE;
  2117. proto->connected_subject = GLOBUS_NULL;
  2118. proto->proxy_connect = proxy ? GLOBUS_TRUE : GLOBUS_FALSE;
  2119. proto->got_response = GLOBUS_FALSE;
  2120. proto->waiting_for_response = GLOBUS_FALSE;
  2121. /* Open the handle */
  2122. if(proxy)
  2123. {
  2124. if(proto->proxy_url.scheme_type == GLOBUS_URL_SCHEME_HTTP &&
  2125. proto->proxy_url.port == 0)
  2126. {
  2127. proto->proxy_url.port = GLOBUS_L_DEFAULT_HTTP_PORT;
  2128. }
  2129. else if(proto->proxy_url.scheme_type == GLOBUS_URL_SCHEME_HTTPS &&
  2130. proto->proxy_url.port == 0)
  2131. {
  2132. proto->proxy_url.port = GLOBUS_L_DEFAULT_HTTPS_PORT;
  2133. }
  2134. debug_printf(4,(_GTSL("%s(): Registering connect to %s\n"),
  2135. myname,
  2136. proto->proxy_url.host));
  2137. result = globus_io_tcp_register_connect(
  2138. proto->proxy_url.host,
  2139. proto->proxy_url.port,
  2140. &tcp_attr,
  2141. globus_l_gass_transfer_http_connect_callback,
  2142. proto,
  2143. &proto->handle);
  2144. }
  2145. else
  2146. {
  2147. if(proto->url.scheme_type == GLOBUS_URL_SCHEME_HTTP &&
  2148. proto->url.port == 0)
  2149. {
  2150. proto->url.port = GLOBUS_L_DEFAULT_HTTP_PORT;
  2151. }
  2152. else if(proto->url.scheme_type == GLOBUS_URL_SCHEME_HTTPS &&
  2153. proto->url.port == 0)
  2154. {
  2155. proto->url.port = GLOBUS_L_DEFAULT_HTTPS_PORT;
  2156. }
  2157. debug_printf(4,(_GTSL("%s(): Registering connect to %s\n"),
  2158. myname,
  2159. proto->url.host));
  2160. result = globus_io_tcp_register_connect(
  2161. proto->url.host,
  2162. proto->url.port,
  2163. &tcp_attr,
  2164. globus_l_gass_transfer_http_connect_callback,
  2165. proto,
  2166. &proto->handle);
  2167. }
  2168. if(proxy)
  2169. {
  2170. globus_url_destroy(&proto->proxy_url);
  2171. }
  2172. if(result != GLOBUS_SUCCESS)
  2173. {
  2174. goto url_error;
  2175. }
  2176. /* Success! */
  2177. globus_io_tcpattr_destroy(&tcp_attr);
  2178. debug_printf(1, (_GTSL("Exiting globus_l_gass_transfer_new_request()\n")));
  2179. return ;
  2180. url_error:
  2181. globus_url_destroy(&proto->url);
  2182. proxy_error:
  2183. if(proxy)
  2184. {
  2185. globus_url_destroy(&proto->proxy_url);
  2186. }
  2187. tcpattr_error:
  2188. globus_io_tcpattr_destroy(&tcp_attr);
  2189. proto_error:
  2190. globus_free(proto);
  2191. error_exit:
  2192. GlobusTimeReltimeSet(delay_time, 0, 0);
  2193. debug_printf(4,(_GTSL("%s(): Registering oneshot\n"),
  2194. myname));
  2195. globus_callback_register_oneshot(
  2196. GLOBUS_NULL,
  2197. &delay_time,
  2198. globus_l_gass_transfer_http_callback_denied,
  2199. (void *) request);
  2200. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2201. }
  2202. /* globus_l_gass_transfer_http_new_request() */
  2203. /*
  2204. * Function: globus_l_gass_transfer_http_new_requestattr()
  2205. *
  2206. * Description: Create a new request attribute structure,
  2207. * appropriate for the "http" url scheme
  2208. *
  2209. * Parameters:
  2210. *
  2211. * Returns:
  2212. */
  2213. static
  2214. globus_object_t *
  2215. globus_l_gass_transfer_http_new_requestattr(
  2216. char * url_scheme)
  2217. {
  2218. globus_object_t * obj;
  2219. MYNAME(globus_l_gass_transfer_http_new_requestattr);
  2220. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  2221. if(strcmp(url_scheme, "https") == 0)
  2222. {
  2223. obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_SECURE_REQUESTATTR);
  2224. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2225. return
  2226. globus_gass_transfer_secure_requestattr_initialize(
  2227. obj,
  2228. GLOBUS_NULL,
  2229. 0,
  2230. GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY,
  2231. GLOBUS_FALSE,
  2232. 0,
  2233. 0,
  2234. GLOBUS_FALSE,
  2235. GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST,
  2236. GLOBUS_NULL);
  2237. }
  2238. else if(strcmp(url_scheme, "http") == 0)
  2239. {
  2240. obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_SOCKET_REQUESTATTR);
  2241. debug_printf(1, (_GTSL("Exiting %s()\n"), myname));
  2242. return
  2243. globus_gass_transfer_socket_requestattr_initialize(
  2244. obj,
  2245. GLOBUS_NULL,
  2246. 0,
  2247. GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY,
  2248. GLOBUS_FALSE,
  2249. 0,
  2250. 0,
  2251. GLOBUS_FALSE);
  2252. }
  2253. else
  2254. {
  2255. debug_printf(1, (_GTSL("Exiting %s()\n"), myname));
  2256. return GLOBUS_NULL;
  2257. }
  2258. }
  2259. /* globus_l_gass_transfer_http_new_requestattr() */
  2260. /*
  2261. * Function: globus_l_gass_transfer_http_new_listenerattr()
  2262. *
  2263. * Description: Create a new listener attribute structure,
  2264. * appropriate for the "http" url scheme
  2265. *
  2266. * Parameters:
  2267. *
  2268. * Returns:
  2269. */
  2270. static
  2271. globus_object_t *
  2272. globus_l_gass_transfer_http_new_listenerattr(
  2273. char * url_scheme)
  2274. {
  2275. globus_object_t * obj;
  2276. MYNAME(globus_l_gass_transfer_http_new_listenerattr);
  2277. debug_printf(1, (_GTSL("Entering %s()\n"), myname));
  2278. if(strcmp(url_scheme, "https") == 0 ||
  2279. strcmp(url_scheme, "http") == 0)
  2280. {
  2281. obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_LISTENERATTR);
  2282. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2283. return
  2284. globus_gass_transfer_listenerattr_initialize(
  2285. obj,
  2286. -1,
  2287. 0);
  2288. }
  2289. else
  2290. {
  2291. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2292. return GLOBUS_NULL;
  2293. }
  2294. }
  2295. /* globus_l_gass_transfer_http_new_listenerattr() */
  2296. /*
  2297. * Function: globus_l_gass_transfer_http_new_listener()
  2298. *
  2299. * Description: Create a new listener structure,
  2300. * appropriate for the "http" and "https" url schemes
  2301. *
  2302. * Parameters:
  2303. *
  2304. * Returns:
  2305. */
  2306. static
  2307. int
  2308. globus_l_gass_transfer_http_new_listener(
  2309. globus_gass_transfer_listener_t listener,
  2310. globus_gass_transfer_listenerattr_t * attr,
  2311. char * scheme,
  2312. char ** base_url,
  2313. globus_gass_transfer_listener_proto_t ** ret_proto)
  2314. {
  2315. globus_gass_transfer_http_listener_proto_t *
  2316. proto;
  2317. globus_io_attr_t tcpattr;
  2318. globus_io_secure_authorization_data_t data;
  2319. globus_result_t result;
  2320. int rc;
  2321. unsigned short port=0;
  2322. int backlog=-1;
  2323. char hostname[MAXHOSTNAMELEN];
  2324. globus_size_t url_size;
  2325. MYNAME(globus_l_gass_transfer_http_new_listener);
  2326. debug_printf(1, (_GTSL("Entering %s()\n"),myname));
  2327. globus_io_tcpattr_init(&tcpattr);
  2328. globus_io_attr_set_socket_keepalive(&tcpattr, GLOBUS_TRUE);
  2329. /* Allocate proto instance */
  2330. proto = (globus_gass_transfer_http_listener_proto_t *)
  2331. globus_malloc(sizeof(globus_gass_transfer_http_listener_proto_t));
  2332. if(proto == GLOBUS_NULL)
  2333. {
  2334. goto free_tcpattr;
  2335. }
  2336. proto->close_listener = globus_l_gass_transfer_http_close_listener;
  2337. proto->listen = globus_l_gass_transfer_http_listen;
  2338. proto->accept = globus_l_gass_transfer_http_accept;
  2339. proto->destroy = globus_l_gass_transfer_http_listener_destroy;
  2340. proto->listener = listener;
  2341. proto->destroy_called = GLOBUS_FALSE;
  2342. if(strcmp(scheme, "http") == 0)
  2343. {
  2344. proto->url_scheme = GLOBUS_URL_SCHEME_HTTP;
  2345. }
  2346. else if(strcmp(scheme, "https") == 0)
  2347. {
  2348. result = globus_io_attr_set_secure_authentication_mode(
  2349. &tcpattr,
  2350. GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
  2351. GLOBUS_NULL);
  2352. if(result != GLOBUS_SUCCESS)
  2353. {
  2354. goto free_proto;
  2355. }
  2356. result = globus_io_attr_set_secure_channel_mode(
  2357. &tcpattr,
  2358. GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
  2359. if(result != GLOBUS_SUCCESS)
  2360. {
  2361. goto free_proto;
  2362. }
  2363. result = globus_io_secure_authorization_data_initialize(&data);
  2364. if(result != GLOBUS_SUCCESS)
  2365. {
  2366. goto free_auth_data;
  2367. }
  2368. result = globus_io_secure_authorization_data_set_callback(
  2369. &data,
  2370. globus_l_gass_transfer_http_authorization_callback,
  2371. proto);
  2372. if(result != GLOBUS_SUCCESS)
  2373. {
  2374. goto free_auth_data;
  2375. }
  2376. result = globus_io_attr_set_secure_authorization_mode(
  2377. &tcpattr,
  2378. GLOBUS_IO_SECURE_AUTHORIZATION_MODE_CALLBACK,
  2379. &data);
  2380. if(result != GLOBUS_SUCCESS)
  2381. {
  2382. goto free_auth_data;
  2383. }
  2384. globus_io_secure_authorization_data_destroy(&data);
  2385. proto->url_scheme = GLOBUS_URL_SCHEME_HTTPS;
  2386. }
  2387. else
  2388. {
  2389. goto free_proto;
  2390. }
  2391. if(attr)
  2392. {
  2393. rc = globus_gass_transfer_listenerattr_get_port(attr,
  2394. &port);
  2395. if(rc != GLOBUS_SUCCESS)
  2396. {
  2397. goto free_proto;
  2398. }
  2399. rc = globus_gass_transfer_listenerattr_get_backlog(attr,
  2400. &backlog);
  2401. if(rc != GLOBUS_SUCCESS)
  2402. {
  2403. goto free_proto;
  2404. }
  2405. }
  2406. result = globus_io_tcp_create_listener(&port,
  2407. backlog,
  2408. &tcpattr,
  2409. &proto->handle);
  2410. globus_io_tcpattr_destroy(&tcpattr);
  2411. if(result != GLOBUS_SUCCESS)
  2412. {
  2413. goto free_proto;
  2414. }
  2415. url_size = 15; /* https://:65536\0 */
  2416. globus_libc_gethostname(hostname,
  2417. MAXHOSTNAMELEN);
  2418. url_size += strlen(hostname);
  2419. *base_url = globus_malloc(url_size);
  2420. sprintf(*base_url,
  2421. "%s://%s:%d",
  2422. proto->url_scheme == GLOBUS_URL_SCHEME_HTTPS ?
  2423. "https" : "http",
  2424. hostname,
  2425. (int) port);
  2426. proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
  2427. *ret_proto = (globus_gass_transfer_listener_proto_t *) proto;
  2428. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2429. return GLOBUS_SUCCESS;
  2430. free_auth_data:
  2431. globus_io_secure_authorization_data_destroy(&data);
  2432. free_proto:
  2433. globus_free(proto);
  2434. free_tcpattr:
  2435. globus_io_tcpattr_destroy(&tcpattr);
  2436. debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
  2437. return GLOBUS_FAILURE;
  2438. }
  2439. /* globus_l_gass_transfer_http_new_listener() */
  2440. /*
  2441. * Function: globus_l_gass_transfer_http_close_listener(()
  2442. *
  2443. * Description: Called by the GASS system when the user has
  2444. * requested that a listener be closed. This
  2445. * may be called at any time, but only once
  2446. * per listener.
  2447. *
  2448. * Parameters:
  2449. *
  2450. * Returns:
  2451. */
  2452. static
  2453. void
  2454. globus_l_gass_transfer_http_close_listener(
  2455. globus_gass_transfer_listener_proto_t * proto,
  2456. globus_gass_transfer_listener_t listener)
  2457. {
  2458. globus_gass_transfer_http_listener_proto_t *
  2459. new_proto;
  2460. MYNAME(globus_l_gass_transfer_http_close_listener);
  2461. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  2462. new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
  2463. globus_l_gass_transfer_http_lock();
  2464. {
  2465. switch(new_proto->state)
  2466. {
  2467. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
  2468. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
  2469. /* If the listener is in the "idle" or "ready" state, then
  2470. * we can simply register the close, which will free the
  2471. * proto. (GASS is not waiting for a callback now.
  2472. */
  2473. globus_l_gass_transfer_http_register_listener_close(new_proto);
  2474. break;
  2475. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
  2476. /*
  2477. * If we are in the "listening" state, registering the
  2478. * close will cause the listen callback to finish, and
  2479. * after that calls the user, the close callback will delete
  2480. * things
  2481. */
  2482. new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1;
  2483. globus_l_gass_transfer_http_register_listener_close(new_proto);
  2484. break;
  2485. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
  2486. /*
  2487. * If we are in the "accepting" state, registering the
  2488. * close will cause any outstanding listen callbacks to finish,
  2489. * from where we can call back to GASS.
  2490. */
  2491. new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2;
  2492. globus_l_gass_transfer_http_register_listener_close(new_proto);
  2493. break;
  2494. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
  2495. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
  2496. case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
  2497. /* should not happen */
  2498. globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1);
  2499. globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2);
  2500. globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED);
  2501. break;
  2502. }
  2503. }
  2504. globus_l_gass_transfer_http_unlock();
  2505. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  2506. return;
  2507. }
  2508. /* globus_l_gass_transfer_http_close_listener() */
  2509. /*
  2510. * Function: globus_l_gass_transfer_http_connect_callback(()
  2511. *
  2512. * Description: Called upon completion of the TCP connect
  2513. * protocol (and the SSL authentication, if
  2514. * applicable).
  2515. *
  2516. * The request string is sent to the server
  2517. * for processing.
  2518. *
  2519. * Parameters:
  2520. *
  2521. * Returns:
  2522. */
  2523. static
  2524. void
  2525. globus_l_gass_transfer_http_connect_callback(
  2526. void * arg,
  2527. globus_io_handle_t * handle,
  2528. globus_result_t result)
  2529. {
  2530. char * cmd;
  2531. globus_gass_transfer_http_request_proto_t * proto;
  2532. globus_gass_transfer_request_t request;
  2533. int code;
  2534. char * msg;
  2535. MYNAME(globus_l_gass_transfer_http_connect_callback);
  2536. debug_printf(3, (_GTSL("Entering %s()\n"), myname));
  2537. /*
  2538. * In this function, we have completed the TCP (and SSL)
  2539. * connection protocol, and will send our request to the
  2540. * server for processing.
  2541. */
  2542. proto = (globus_gass_transfer_http_request_proto_t *)
  2543. arg;
  2544. globus_l_gass_transfer_http_lock();
  2545. globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING);
  2546. if(result != GLOBUS_SUCCESS)
  2547. {
  2548. /*
  2549. * TODO: Evaluate error object here, put into
  2550. * proto->code and proto->reason
  2551. */
  2552. goto deny_exit;
  2553. }
  2554. cmd = globus_l_gass_transfer_http_construct_request(proto);
  2555. if(cmd == GLOBUS_NULL)
  2556. {
  2557. goto deny_exit;
  2558. }
  2559. /* Send our command to the server */
  2560. debug_printf(4,(_GTSL("%s(): Registering write on %p\n"),
  2561. myname,
  2562. &proto->handle));
  2563. result = globus_io_register_write(
  2564. &proto->handle,
  2565. (globus_byte_t *) cmd,
  2566. strlen(cmd) * sizeof(char),
  2567. globus_l_gass_transfer_http_command_callback,
  2568. proto);
  2569. if(result == GLOBUS_SUCCESS)
  2570. {
  2571. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING;
  2572. globus_l_gass_transfer_http_unlock();
  2573. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  2574. return;
  2575. }
  2576. /* Write registration failed, fall through to deny_exit */
  2577. deny_exit:
  2578. /* Give a default error message, if none is generated above */
  2579. if(proto->code == 0)
  2580. {
  2581. proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
  2582. proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
  2583. }
  2584. /*
  2585. * Because the proto is not being returned in a request ready,
  2586. * we must not wait for the GASS system to call the destroyed
  2587. * method of the proto
  2588. */
  2589. proto->destroy_called=GLOBUS_TRUE;
  2590. request = proto->request;
  2591. code = proto->code;
  2592. msg = globus_libc_strdup(proto->reason);
  2593. result = globus_l_gass_transfer_http_register_close(proto);
  2594. if (result != GLOBUS_SUCCESS)
  2595. {
  2596. globus_l_gass_transfer_http_close(proto);
  2597. }
  2598. globus_l_gass_transfer_http_unlock();
  2599. /* Signal Denial to the GASS system */
  2600. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
  2601. globus_gass_transfer_proto_request_denied(
  2602. request,
  2603. code,
  2604. msg);
  2605. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  2606. }
  2607. /* globus_l_gass_transfer_http_connect_callback() */
  2608. /*
  2609. * Function: globus_l_gass_transfer_http_command_callback(()
  2610. *
  2611. * Description: Called when the HTTP request has been sent
  2612. * to the server for processing.
  2613. *
  2614. * The request string is sent to the server
  2615. * for processing.
  2616. *
  2617. * Parameters:
  2618. *
  2619. * Returns:
  2620. */
  2621. static
  2622. void
  2623. globus_l_gass_transfer_http_command_callback(
  2624. void * arg,
  2625. globus_io_handle_t * handle,
  2626. globus_result_t result,
  2627. globus_byte_t * buf,
  2628. globus_size_t nbytes)
  2629. {
  2630. globus_gass_transfer_http_request_proto_t * proto;
  2631. globus_gass_transfer_request_t request;
  2632. int code;
  2633. char * reason;
  2634. MYNAME(globus_l_gass_transfer_http_command_callback);
  2635. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  2636. /*
  2637. * In this function, we have completed sending our request
  2638. * to the server. If there was some sort of error, we
  2639. * will signal a "deny" to the server.
  2640. */
  2641. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  2642. globus_l_gass_transfer_http_lock();
  2643. globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING);
  2644. if(result != GLOBUS_SUCCESS)
  2645. {
  2646. goto deny_exit;
  2647. }
  2648. /*
  2649. * Free the request command buffer.
  2650. */
  2651. globus_free(buf);
  2652. buf = GLOBUS_NULL;
  2653. /*
  2654. * We will now register a response handling buffer & callback
  2655. * The buffer may have to grow if there are a lot of headers.
  2656. */
  2657. proto->response_buffer = globus_malloc(GLOBUS_L_GASS_RESPONSE_LEN *
  2658. sizeof(globus_byte_t));
  2659. proto->response_buflen = GLOBUS_L_GASS_RESPONSE_LEN;
  2660. proto->response_offset = 0;
  2661. proto->parsed_offset = 0;
  2662. switch(proto->type)
  2663. {
  2664. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
  2665. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
  2666. /*
  2667. * If we are a "put" or "append" request, then we can start
  2668. * sending data sort of immediately. So we send an "ready"
  2669. * message to the server. A little optimistic, perhaps...
  2670. * We will not register for the response message until
  2671. * we've sent the last data.
  2672. */
  2673. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  2674. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  2675. myname,
  2676. &proto->handle));
  2677. result = globus_io_register_read(
  2678. &proto->handle,
  2679. proto->response_buffer,
  2680. proto->response_buflen,
  2681. 1,
  2682. globus_l_gass_transfer_http_response_callback,
  2683. proto);
  2684. if(result != GLOBUS_SUCCESS)
  2685. {
  2686. proto->failure_occurred = GLOBUS_TRUE;
  2687. }
  2688. globus_l_gass_transfer_http_unlock();
  2689. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
  2690. globus_gass_transfer_proto_request_ready(
  2691. proto->request,
  2692. (globus_gass_transfer_request_proto_t *) proto);
  2693. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  2694. return;
  2695. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
  2696. /*
  2697. * If we are a "GET" request we can't do anything
  2698. * until the server sends us some info, anyway
  2699. */
  2700. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  2701. myname,
  2702. &proto->handle));
  2703. result = globus_io_register_read(
  2704. &proto->handle,
  2705. proto->response_buffer,
  2706. proto->response_buflen,
  2707. 1,
  2708. globus_l_gass_transfer_http_response_callback,
  2709. proto);
  2710. if(result != GLOBUS_SUCCESS)
  2711. {
  2712. /* should interpret the error object */
  2713. goto deny_exit;
  2714. }
  2715. globus_l_gass_transfer_http_unlock();
  2716. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  2717. return;
  2718. default:
  2719. globus_assert(proto->type !=
  2720. GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
  2721. goto deny_exit;
  2722. }
  2723. deny_exit:
  2724. if(buf != GLOBUS_NULL)
  2725. {
  2726. globus_libc_free(buf);
  2727. buf = GLOBUS_NULL;
  2728. }
  2729. /* Give a default error message, if none is generated above */
  2730. if(proto->code == 0)
  2731. {
  2732. proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
  2733. proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
  2734. }
  2735. request = proto->request;
  2736. code = proto->code;
  2737. reason = globus_libc_strdup(proto->reason);
  2738. result = globus_l_gass_transfer_http_register_close(proto);
  2739. if (result != GLOBUS_SUCCESS)
  2740. {
  2741. globus_l_gass_transfer_http_close(proto);
  2742. }
  2743. globus_l_gass_transfer_http_unlock();
  2744. /* Signal Denial to the GASS system */
  2745. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
  2746. globus_gass_transfer_proto_request_denied(
  2747. request,
  2748. code,
  2749. reason);
  2750. debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
  2751. }
  2752. /* globus_l_gass_transfer_http_command_callback() */
  2753. static
  2754. void
  2755. globus_l_gass_transfer_http_response_callback(
  2756. void * arg,
  2757. globus_io_handle_t * handle,
  2758. globus_result_t result,
  2759. globus_byte_t * buf,
  2760. globus_size_t nbytes)
  2761. {
  2762. globus_gass_transfer_http_request_proto_t * proto;
  2763. globus_object_t * err=GLOBUS_NULL;
  2764. globus_gass_transfer_request_t request;
  2765. int code;
  2766. char * reason;
  2767. MYNAME(globus_l_gass_transfer_http_response_callback);
  2768. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  2769. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  2770. if(result != GLOBUS_SUCCESS)
  2771. {
  2772. char * tmpstr;
  2773. err = globus_error_get(result);
  2774. tmpstr = globus_object_printable_to_string(err);
  2775. debug_printf(5, (_GTSL("globus_l_gass_transfer_http_read_callback(): %s"), tmpstr));
  2776. globus_libc_free(tmpstr);
  2777. }
  2778. globus_l_gass_transfer_http_lock();
  2779. request = proto->request;
  2780. /* Did the read succeed? */
  2781. if(result != GLOBUS_SUCCESS &&
  2782. !globus_io_eof(err))
  2783. {
  2784. if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  2785. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
  2786. {
  2787. goto put_fail_exit;
  2788. }
  2789. result = globus_l_gass_transfer_http_register_close(proto);
  2790. if (result != GLOBUS_SUCCESS)
  2791. {
  2792. globus_l_gass_transfer_http_close(proto);
  2793. }
  2794. globus_l_gass_transfer_http_unlock();
  2795. /* TODO: Evaluate error object, or response from the server here */
  2796. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
  2797. globus_gass_transfer_proto_request_denied(
  2798. request,
  2799. GLOBUS_L_DEFAULT_FAILURE_CODE,
  2800. globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON));
  2801. if(err)
  2802. {
  2803. globus_object_free(err);
  2804. }
  2805. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  2806. return;
  2807. }
  2808. /* Update our counters */
  2809. proto->response_offset += nbytes;
  2810. do
  2811. {
  2812. /* Parse the buffer that we have */
  2813. if(globus_l_gass_transfer_http_parse_response(proto))
  2814. {
  2815. /* returns true, if we need to read some more */
  2816. goto repost_read;
  2817. }
  2818. switch(proto->type)
  2819. {
  2820. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
  2821. /* If it is a GET request, we need an affirmative
  2822. * response, or a continue, or a referral
  2823. */
  2824. if(proto->code < 100 ||
  2825. proto->code >= 400)
  2826. {
  2827. /* Denied */
  2828. goto deny_exit;
  2829. }
  2830. else if(proto->code >= 100 &&
  2831. proto->code < 200)
  2832. {
  2833. /*
  2834. * Continue... Reset our response buffers,
  2835. * and get another set of headers
  2836. */
  2837. memmove(proto->response_buffer,
  2838. proto->response_buffer + proto->parsed_offset,
  2839. proto->response_offset - proto->parsed_offset);
  2840. proto->response_offset -= proto->parsed_offset;
  2841. proto->parsed_offset = 0;
  2842. if(proto->reason)
  2843. {
  2844. globus_free(proto->reason);
  2845. }
  2846. proto->code = 0;
  2847. proto->reason = GLOBUS_NULL;
  2848. globus_i_gass_transfer_keyvalue_destroy(
  2849. &proto->headers);
  2850. /*
  2851. * There may be more headers in our buffer, so
  2852. * we should go through the parse loop again,
  2853. * maybe
  2854. */
  2855. if(proto->response_offset != 0)
  2856. {
  2857. continue;
  2858. }
  2859. else
  2860. {
  2861. goto repost_read;
  2862. }
  2863. }
  2864. else if(proto->code >= 300 &&
  2865. proto->code < 400)
  2866. {
  2867. char ** referral;
  2868. globus_size_t referral_count;
  2869. /* We've got a referral from the server */
  2870. globus_l_gass_transfer_http_extract_referral(proto,
  2871. &referral,
  2872. &referral_count);
  2873. if(referral == GLOBUS_NULL)
  2874. {
  2875. goto deny_exit;
  2876. }
  2877. else
  2878. {
  2879. /* If this is a get request, then the proto layer
  2880. * doesn't have a pointer to this proto yet,
  2881. * so we need to act like they've destroyed their
  2882. * reference to it
  2883. */
  2884. proto->destroy_called = GLOBUS_TRUE;
  2885. result = globus_l_gass_transfer_http_register_close(proto);
  2886. if (result != GLOBUS_SUCCESS)
  2887. {
  2888. globus_l_gass_transfer_http_close(proto);
  2889. }
  2890. globus_l_gass_transfer_http_unlock();
  2891. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
  2892. globus_gass_transfer_proto_request_referred(
  2893. request,
  2894. referral,
  2895. referral_count);
  2896. return;
  2897. }
  2898. }
  2899. else
  2900. {
  2901. /*
  2902. * Successful response for the "get", check for
  2903. * interesting headers, and indicate "ready" to
  2904. * the GASS system. (note that first read will
  2905. * have to deal with the data in
  2906. * proto->response_buffer)
  2907. */
  2908. char * value;
  2909. /*
  2910. * Look to see if there are any headers we
  2911. * care about
  2912. */
  2913. value = globus_i_gass_transfer_keyvalue_lookup(
  2914. &proto->headers,
  2915. "transfer-encoding");
  2916. if(value)
  2917. {
  2918. char * tmp;
  2919. for(tmp = value; *tmp != '\0'; tmp++)
  2920. {
  2921. if(! isspace(*tmp))
  2922. {
  2923. break;
  2924. }
  2925. }
  2926. #ifndef TARGET_ARCH_WIN32
  2927. if(strncasecmp(tmp, "chunked", strlen("chunked")) == 0)
  2928. #else
  2929. if(strnicmp(tmp, "chunked", strlen("chunked")) == 0)
  2930. #endif
  2931. {
  2932. proto->recv_buffer =
  2933. globus_l_gass_transfer_http_receive;
  2934. proto->chunked = GLOBUS_TRUE;
  2935. proto->recv_state =
  2936. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
  2937. proto->length = 0;
  2938. }
  2939. }
  2940. if(!proto->chunked)
  2941. {
  2942. /* If both
  2943. * Transfer-Encoding: chunked and
  2944. * Content-Length: <something>
  2945. * are passed, the Content-length should be ignored,
  2946. * according to RFC 2068
  2947. */
  2948. value = globus_i_gass_transfer_keyvalue_lookup(
  2949. &proto->headers,
  2950. "content-length");
  2951. if(value)
  2952. {
  2953. int save_errno;
  2954. char * tmp;
  2955. for(tmp = value; *tmp != '\0'; tmp++)
  2956. {
  2957. if(! isspace(*tmp))
  2958. {
  2959. break;
  2960. }
  2961. }
  2962. globus_libc_lock();
  2963. errno=0;
  2964. proto->length = strtoul(tmp,
  2965. GLOBUS_NULL,
  2966. 10);
  2967. save_errno=errno;
  2968. globus_libc_unlock();
  2969. if(save_errno != 0)
  2970. {
  2971. proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
  2972. proto->reason = globus_libc_strdup(
  2973. GLOBUS_L_PROTOCOL_FAILURE_REASON);
  2974. goto deny_exit;
  2975. }
  2976. if(proto->length == 0)
  2977. {
  2978. proto->recv_state =
  2979. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  2980. }
  2981. else
  2982. {
  2983. proto->recv_state =
  2984. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH;
  2985. }
  2986. }
  2987. else
  2988. {
  2989. proto->recv_state =
  2990. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF;
  2991. }
  2992. if(!proto->text_mode)
  2993. {
  2994. globus_gass_transfer_request_set_length(proto->request,
  2995. proto->length);
  2996. }
  2997. }
  2998. /*
  2999. * The response buffer's residue may contain some
  3000. * entity information, so let's keep it around.
  3001. * Also, if we are in text mode, we'll have to copy
  3002. * the data anyway (but should use the block_size)
  3003. */
  3004. if(proto->text_mode &&
  3005. proto->block_size > proto->response_buflen)
  3006. {
  3007. globus_byte_t * tmp;
  3008. tmp = globus_libc_realloc(proto->response_buffer,
  3009. proto->block_size *
  3010. sizeof(globus_byte_t));
  3011. if(tmp != GLOBUS_NULL)
  3012. {
  3013. proto->response_buffer = tmp;
  3014. proto->response_buflen = proto->block_size;
  3015. }
  3016. }
  3017. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  3018. globus_l_gass_transfer_http_unlock();
  3019. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready"))); globus_gass_transfer_proto_request_ready(
  3020. proto->request,
  3021. (globus_gass_transfer_request_proto_t *) proto);
  3022. }
  3023. break;
  3024. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
  3025. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
  3026. /* If it is a PUT or APPEND request, we don't expect any
  3027. * response from the server until we're done sending,
  3028. * or the server kills our request
  3029. */
  3030. if(proto->code < 100 ||
  3031. proto->code >= 400)
  3032. {
  3033. /* Request failed. */
  3034. goto put_fail_exit;
  3035. }
  3036. else if(proto->code >= 300 &&
  3037. proto->code < 400)
  3038. {
  3039. char ** referral;
  3040. globus_size_t referral_count;
  3041. /* Request referred. */
  3042. globus_l_gass_transfer_http_extract_referral(proto,
  3043. &referral,
  3044. &referral_count);
  3045. if(referral == GLOBUS_NULL)
  3046. {
  3047. goto put_fail_exit;
  3048. }
  3049. else if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE)
  3050. {
  3051. result = globus_l_gass_transfer_http_register_close(proto);
  3052. if (result != GLOBUS_SUCCESS)
  3053. {
  3054. globus_l_gass_transfer_http_close(proto);
  3055. }
  3056. globus_l_gass_transfer_http_unlock();
  3057. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
  3058. globus_gass_transfer_proto_request_referred(request,
  3059. referral,
  3060. referral_count);
  3061. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3062. return;
  3063. }
  3064. else
  3065. {
  3066. proto->failure_occurred = GLOBUS_TRUE;
  3067. result = globus_l_gass_transfer_http_register_close(proto);
  3068. if (result != GLOBUS_SUCCESS)
  3069. {
  3070. globus_l_gass_transfer_http_close(proto);
  3071. }
  3072. globus_l_gass_transfer_http_unlock();
  3073. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
  3074. globus_gass_transfer_proto_request_referred(request,
  3075. referral,
  3076. referral_count);
  3077. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3078. return;
  3079. }
  3080. }
  3081. else if(proto->code >= 100 &&
  3082. proto->code < 200)
  3083. {
  3084. /*
  3085. * Continue... Reset our response buffers,
  3086. * and get another set of headers
  3087. */
  3088. memmove(proto->response_buffer,
  3089. proto->response_buffer + proto->parsed_offset,
  3090. proto->response_offset - proto->parsed_offset);
  3091. proto->response_offset -= proto->parsed_offset;
  3092. proto->parsed_offset = 0;
  3093. if(proto->reason)
  3094. {
  3095. globus_free(proto->reason);
  3096. }
  3097. proto->code = 0;
  3098. proto->reason = GLOBUS_NULL;
  3099. globus_i_gass_transfer_keyvalue_destroy(
  3100. &proto->headers);
  3101. /*
  3102. * There may be more headers in our buffer, so
  3103. * we should go through the parse loop again,
  3104. * maybe
  3105. */
  3106. if(proto->response_offset != 0)
  3107. {
  3108. continue;
  3109. }
  3110. else
  3111. {
  3112. goto repost_read;
  3113. }
  3114. }
  3115. else
  3116. {
  3117. goto put_success_exit;
  3118. }
  3119. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID:
  3120. default:
  3121. globus_assert(proto->type !=
  3122. GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
  3123. globus_assert(GLOBUS_FALSE);
  3124. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3125. return;
  3126. }
  3127. }
  3128. while(proto->code == 0 ||
  3129. proto->code == 100);
  3130. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3131. return;
  3132. repost_read:
  3133. if(result != GLOBUS_NULL)
  3134. {
  3135. proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
  3136. proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
  3137. if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
  3138. proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
  3139. {
  3140. goto put_fail_exit;
  3141. }
  3142. else
  3143. {
  3144. goto deny_exit;
  3145. }
  3146. }
  3147. /* Reallocate a larger buffer, if we need to */
  3148. if(proto->response_buflen == proto->response_offset)
  3149. {
  3150. globus_byte_t * tmp;
  3151. tmp = globus_libc_realloc(proto->response_buffer,
  3152. proto->response_buflen *
  3153. 2 *
  3154. sizeof(globus_byte_t));
  3155. if(tmp == GLOBUS_NULL)
  3156. {
  3157. proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
  3158. proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
  3159. goto deny_exit;
  3160. }
  3161. else
  3162. {
  3163. proto->response_buffer = tmp;
  3164. proto->response_buflen *= 2;
  3165. }
  3166. }
  3167. /* Register another read */
  3168. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  3169. myname,
  3170. &proto->handle));
  3171. result = globus_io_register_read(&proto->handle,
  3172. proto->response_buffer +
  3173. proto->response_offset,
  3174. proto->response_buflen -
  3175. proto->response_offset,
  3176. 1,
  3177. globus_l_gass_transfer_http_response_callback,
  3178. proto);
  3179. if(result != GLOBUS_SUCCESS)
  3180. {
  3181. /* TODO interpret the error object */
  3182. goto deny_exit;
  3183. }
  3184. globus_l_gass_transfer_http_unlock();
  3185. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3186. return;
  3187. deny_exit:
  3188. if(err)
  3189. {
  3190. globus_object_free(err);
  3191. }
  3192. /*
  3193. * Because the proto is not being returned in a request ready,
  3194. * we must not wait for the GASS system to call the destroyed
  3195. * method of the proto
  3196. */
  3197. proto->destroy_called=GLOBUS_TRUE;
  3198. code = proto->code;
  3199. reason = globus_libc_strdup(proto->reason);
  3200. result = globus_l_gass_transfer_http_register_close(proto);
  3201. if (result != GLOBUS_SUCCESS)
  3202. {
  3203. globus_l_gass_transfer_http_close(proto);
  3204. }
  3205. globus_l_gass_transfer_http_unlock();
  3206. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
  3207. globus_gass_transfer_proto_request_denied(request,
  3208. code,
  3209. reason);
  3210. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3211. return;
  3212. put_success_exit:
  3213. {
  3214. globus_byte_t * buffer;
  3215. globus_size_t offset;
  3216. globus_bool_t failure;
  3217. buffer = proto->user_buffer;
  3218. offset = proto->user_offset;
  3219. failure = proto->failure_occurred;
  3220. /*
  3221. * success response from a server, signal this to the GASS system
  3222. */
  3223. globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING);
  3224. result = globus_l_gass_transfer_http_register_close(proto);
  3225. if (result != GLOBUS_SUCCESS)
  3226. {
  3227. globus_l_gass_transfer_http_close(proto);
  3228. }
  3229. globus_l_gass_transfer_http_unlock();
  3230. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
  3231. globus_gass_transfer_proto_send_complete(request,
  3232. buffer,
  3233. offset,
  3234. failure,
  3235. GLOBUS_TRUE);
  3236. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3237. return;
  3238. }
  3239. put_fail_exit:
  3240. /*
  3241. * request failed after a put or append operation. We
  3242. * need to signal the failure to the GASS system
  3243. */
  3244. proto->got_response = GLOBUS_TRUE;
  3245. proto->failure_occurred = GLOBUS_TRUE;
  3246. if(proto->waiting_for_response)
  3247. {
  3248. globus_byte_t * buffer;
  3249. globus_size_t offset;
  3250. int failed = proto->failure_occurred;
  3251. buffer = proto->user_buffer;
  3252. offset = proto->user_offset;
  3253. result = globus_l_gass_transfer_http_register_close(proto);
  3254. if (result != GLOBUS_SUCCESS)
  3255. {
  3256. globus_l_gass_transfer_http_close(proto);
  3257. }
  3258. globus_l_gass_transfer_http_unlock();
  3259. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
  3260. globus_gass_transfer_proto_send_complete(request,
  3261. buffer,
  3262. offset,
  3263. failed,
  3264. GLOBUS_TRUE);
  3265. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3266. return;
  3267. }
  3268. else
  3269. {
  3270. proto->failure_occurred = GLOBUS_TRUE;
  3271. globus_l_gass_transfer_http_unlock();
  3272. }
  3273. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
  3274. }
  3275. /* globus_l_gass_transfer_http_response_callback() */
  3276. static
  3277. void
  3278. globus_l_gass_transfer_http_request_callback(
  3279. void * arg,
  3280. globus_io_handle_t * handle,
  3281. globus_result_t result,
  3282. globus_byte_t * buf,
  3283. globus_size_t nbytes)
  3284. {
  3285. globus_gass_transfer_http_request_proto_t * proto;
  3286. globus_gass_transfer_http_listener_proto_t * l_proto;
  3287. globus_object_t * err=GLOBUS_NULL;
  3288. char * value;
  3289. globus_gass_transfer_request_t request;
  3290. MYNAME(globus_l_gass_transfer_http_request_callback);
  3291. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  3292. l_proto = (globus_gass_transfer_http_listener_proto_t *) arg;
  3293. proto = l_proto->request;
  3294. if(result != GLOBUS_SUCCESS)
  3295. {
  3296. char * tmpstr;
  3297. err = globus_error_get(result);
  3298. tmpstr = globus_object_printable_to_string(err);
  3299. debug_printf(5, (_GTSL("globus_l_gass_transfer_http_read_callback(): %s"), tmpstr));
  3300. globus_libc_free(tmpstr);
  3301. }
  3302. globus_l_gass_transfer_http_lock();
  3303. request = proto->request;
  3304. /* Did the read succeed? */
  3305. if(result != GLOBUS_SUCCESS &&
  3306. !globus_io_eof(err))
  3307. {
  3308. goto deny_exit;
  3309. }
  3310. /* Update our counters */
  3311. proto->response_offset += nbytes;
  3312. /* Parse the buffer that we have */
  3313. if(globus_l_gass_transfer_http_parse_request(proto))
  3314. {
  3315. /* returns true, if we need to read some more */
  3316. if(proto->parsed_offset == 0 &&
  3317. proto->response_offset > 0 &&
  3318. !isupper(proto->response_buffer[0]))
  3319. {
  3320. goto deny_exit;
  3321. }
  3322. goto repost_read;
  3323. }
  3324. else if(proto->parse_error)
  3325. {
  3326. goto deny_exit;
  3327. }
  3328. else if(strcmp(proto->uri, "*") == 0)
  3329. {
  3330. /* Request we don't handle */
  3331. goto deny_exit;
  3332. }
  3333. else if(strcmp(proto->method, "GET") == 0)
  3334. {
  3335. proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET;
  3336. }
  3337. else if(strcmp(proto->method, "PUT") == 0)
  3338. {
  3339. proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT;
  3340. }
  3341. else if(strcmp(proto->method, "POST") == 0 &&
  3342. strncmp(proto->uri,
  3343. GLOBUS_L_APPEND_URI,
  3344. strlen(GLOBUS_L_APPEND_URI)) == 0)
  3345. {
  3346. globus_size_t append_len;
  3347. globus_size_t uri_len;
  3348. append_len = strlen(GLOBUS_L_APPEND_URI);
  3349. uri_len = strlen(proto->uri) - strlen(GLOBUS_L_APPEND_URI);
  3350. proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND;
  3351. memmove(proto->uri,
  3352. proto->uri + append_len,
  3353. uri_len);
  3354. proto->uri[uri_len] = '\0';
  3355. }
  3356. else
  3357. {
  3358. /* Unknown/Unsupported method */
  3359. goto deny_exit;
  3360. }
  3361. globus_gass_transfer_request_set_type(proto->request,
  3362. proto->type);
  3363. /* Construct URL for this request */
  3364. if(strncmp(proto->uri, "https://", strlen("https://")) == 0 ||
  3365. strncmp(proto->uri, "http://", strlen("http://")) == 0)
  3366. {
  3367. globus_gass_transfer_request_set_url(proto->request,
  3368. proto->uri);
  3369. }
  3370. else
  3371. {
  3372. char * url_base;
  3373. char * url;
  3374. url_base = globus_gass_transfer_listener_get_base_url(l_proto->listener);
  3375. url = globus_malloc(strlen(url_base) + strlen(proto->uri) + 1);
  3376. sprintf(url, "%s%s", url_base, proto->uri);
  3377. globus_gass_transfer_request_set_url(proto->request,
  3378. url);
  3379. }
  3380. /*
  3381. * Look to see if there are any headers we
  3382. * care about
  3383. */
  3384. value = globus_i_gass_transfer_keyvalue_lookup(
  3385. &proto->headers,
  3386. "transfer-encoding");
  3387. if(value)
  3388. {
  3389. char * tmp;
  3390. for(tmp = value; *tmp != '\0'; tmp++)
  3391. {
  3392. if(! isspace(*tmp))
  3393. {
  3394. break;
  3395. }
  3396. }
  3397. #ifndef TARGET_ARCH_WIN32
  3398. if(strncasecmp(tmp, "chunked", strlen("chunked")) == 0)
  3399. #else
  3400. if(strnicmp(tmp, "chunked", strlen("chunked")) == 0)
  3401. #endif
  3402. {
  3403. proto->recv_buffer =
  3404. globus_l_gass_transfer_http_receive;
  3405. proto->chunked = GLOBUS_TRUE;
  3406. proto->recv_state =
  3407. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
  3408. proto->length = 0;
  3409. }
  3410. }
  3411. if(!proto->chunked)
  3412. {
  3413. /* If both
  3414. * Transfer-Encoding: chunked and
  3415. * Content-Length: <something>
  3416. * are passed, the Content-length should be ignored,
  3417. * according to RFC 2068
  3418. */
  3419. value = globus_i_gass_transfer_keyvalue_lookup(
  3420. &proto->headers,
  3421. "content-length");
  3422. if(value)
  3423. {
  3424. int save_errno;
  3425. char * tmp;
  3426. for(tmp = value; *tmp != '\0'; tmp++)
  3427. {
  3428. if(! isspace(*tmp))
  3429. {
  3430. break;
  3431. }
  3432. }
  3433. globus_libc_lock();
  3434. errno=0;
  3435. proto->length = strtoul(tmp,
  3436. GLOBUS_NULL,
  3437. 10);
  3438. save_errno=errno;
  3439. globus_libc_unlock();
  3440. if(save_errno != 0)
  3441. {
  3442. proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
  3443. proto->reason = globus_libc_strdup(
  3444. GLOBUS_L_PROTOCOL_FAILURE_REASON);
  3445. goto deny_exit;
  3446. }
  3447. if(proto->length == 0)
  3448. {
  3449. proto->recv_state =
  3450. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  3451. }
  3452. else
  3453. {
  3454. proto->recv_state =
  3455. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH;
  3456. }
  3457. }
  3458. else
  3459. {
  3460. proto->recv_state =
  3461. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF;
  3462. }
  3463. if(!proto->text_mode)
  3464. {
  3465. globus_gass_transfer_request_set_length(proto->request,
  3466. proto->length);
  3467. }
  3468. }
  3469. /*
  3470. * The response buffer's residue may contain some
  3471. * entity information, so let's keep it around.
  3472. * Also, if we are in text mode, we'll have to copy
  3473. * the data anyway (but should use the block_size)
  3474. */
  3475. if(proto->text_mode &&
  3476. proto->block_size > proto->response_buflen)
  3477. {
  3478. globus_byte_t * tmp;
  3479. tmp = globus_libc_realloc(proto->response_buffer,
  3480. proto->block_size *
  3481. sizeof(globus_byte_t));
  3482. if(tmp != GLOBUS_NULL)
  3483. {
  3484. proto->response_buffer = tmp;
  3485. proto->response_buflen = proto->block_size;
  3486. }
  3487. }
  3488. /* We now have a request, callback to user */
  3489. l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
  3490. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
  3491. if(proto->connected_subject)
  3492. {
  3493. globus_gass_transfer_request_set_subject(proto->request,
  3494. globus_libc_strdup(proto->connected_subject));
  3495. }
  3496. globus_l_gass_transfer_http_unlock();
  3497. globus_gass_transfer_proto_new_listener_request(
  3498. l_proto->listener,
  3499. proto->request,
  3500. (globus_gass_transfer_request_proto_t *) proto);
  3501. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
  3502. return;
  3503. repost_read:
  3504. if(result != GLOBUS_NULL)
  3505. {
  3506. goto deny_exit;
  3507. }
  3508. /* Reallocate a larger buffer, if we need to */
  3509. if(proto->response_buflen == proto->response_offset)
  3510. {
  3511. globus_byte_t * tmp;
  3512. tmp = globus_libc_realloc(proto->response_buffer,
  3513. proto->response_buflen *
  3514. 2 *
  3515. sizeof(globus_byte_t));
  3516. if(tmp == GLOBUS_NULL)
  3517. {
  3518. proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
  3519. proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
  3520. goto deny_exit;
  3521. }
  3522. else
  3523. {
  3524. proto->response_buffer = tmp;
  3525. proto->response_buflen *= 2;
  3526. }
  3527. }
  3528. /* Register another read */
  3529. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  3530. myname,
  3531. &proto->handle));
  3532. result = globus_io_register_read(&proto->handle,
  3533. proto->response_buffer +
  3534. proto->response_offset,
  3535. proto->response_buflen -
  3536. proto->response_offset,
  3537. 1,
  3538. globus_l_gass_transfer_http_request_callback,
  3539. l_proto);
  3540. if(result != GLOBUS_SUCCESS)
  3541. {
  3542. /* TODO interpret the error object */
  3543. goto deny_exit;
  3544. }
  3545. globus_l_gass_transfer_http_unlock();
  3546. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
  3547. return;
  3548. deny_exit:
  3549. if(err)
  3550. {
  3551. globus_object_free(err);
  3552. }
  3553. /*
  3554. * Since we are the server we must fail this request by calling
  3555. * new_listener with a NULL proto
  3556. */
  3557. proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
  3558. /*
  3559. * Because the proto is not being returned in a request ready,
  3560. * we must not wait for the GASS system to call the destroyed
  3561. * method of the proto
  3562. */
  3563. proto->destroy_called=GLOBUS_TRUE;
  3564. result = globus_l_gass_transfer_http_register_close(proto);
  3565. if (result != GLOBUS_SUCCESS)
  3566. {
  3567. globus_l_gass_transfer_http_close(proto);
  3568. }
  3569. globus_l_gass_transfer_http_unlock();
  3570. globus_gass_transfer_proto_new_listener_request(
  3571. l_proto->listener,
  3572. request,
  3573. (globus_gass_transfer_request_proto_t *) GLOBUS_NULL);
  3574. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
  3575. return;
  3576. }
  3577. /* globus_l_gass_transfer_http_request_callback() */
  3578. static
  3579. void
  3580. globus_l_gass_transfer_http_callback_send_callback(
  3581. void * arg)
  3582. {
  3583. globus_gass_transfer_http_request_proto_t * proto;
  3584. MYNAME(globus_l_gass_transfer_http_callback_send_callback);
  3585. debug_printf(3, (_GTSL("Entering %s()\n"),myname));
  3586. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  3587. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
  3588. globus_gass_transfer_proto_send_complete(proto->request,
  3589. proto->user_buffer,
  3590. proto->user_offset,
  3591. proto->failure_occurred,
  3592. proto->failure_occurred);
  3593. debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_callback_send_callback()\n")));
  3594. }
  3595. static
  3596. void
  3597. globus_l_gass_transfer_http_callback_ready_callback(
  3598. void * arg)
  3599. {
  3600. globus_gass_transfer_http_request_proto_t * proto;
  3601. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  3602. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
  3603. globus_gass_transfer_proto_request_ready(proto->request,
  3604. (globus_gass_transfer_request_proto_t *) proto);
  3605. }
  3606. /* globus_l_gass_transfer_http_callback_read_buffered_callback() */
  3607. static
  3608. void
  3609. globus_l_gass_transfer_http_callback_read_buffered_callback(
  3610. void * arg)
  3611. {
  3612. globus_gass_transfer_http_request_proto_t * proto;
  3613. proto = (globus_gass_transfer_http_request_proto_t *) arg;
  3614. globus_l_gass_transfer_http_lock();
  3615. proto->oneshot_registered = GLOBUS_FALSE;
  3616. proto->oneshot_active = GLOBUS_TRUE;
  3617. globus_l_gass_transfer_http_unlock();
  3618. globus_l_gass_transfer_http_read_buffered_callback(arg,
  3619. &proto->handle,
  3620. GLOBUS_SUCCESS,
  3621. proto->response_buffer +
  3622. proto->response_offset,
  3623. 0);
  3624. }
  3625. /* globus_l_gass_transfer_http_callback_read_buffered_callback() */
  3626. static
  3627. void
  3628. globus_l_gass_transfer_http_callback_listen_callback(
  3629. void * arg)
  3630. {
  3631. globus_gass_transfer_http_listener_proto_t *proto;
  3632. globus_gass_transfer_listener_t listener;
  3633. proto = (globus_gass_transfer_http_listener_proto_t *) arg;
  3634. globus_l_gass_transfer_http_lock();
  3635. if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING)
  3636. {
  3637. proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY;
  3638. }
  3639. listener = proto->listener;
  3640. globus_l_gass_transfer_http_unlock();
  3641. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_listener_ready()")));
  3642. globus_gass_transfer_proto_listener_ready(listener);
  3643. }
  3644. /* globus_l_gass_transfer_http_callback_listen_callback() */
  3645. static
  3646. void
  3647. globus_l_gass_transfer_http_accept(
  3648. globus_gass_transfer_listener_proto_t * proto,
  3649. globus_gass_transfer_listener_t listener,
  3650. globus_gass_transfer_request_t request,
  3651. globus_gass_transfer_requestattr_t * attr)
  3652. {
  3653. globus_result_t result;
  3654. globus_io_attr_t tcp_attr;
  3655. globus_gass_transfer_http_listener_proto_t *
  3656. l_proto;
  3657. int rc;
  3658. int sndbuf;
  3659. int rcvbuf;
  3660. globus_bool_t nodelay;
  3661. globus_gass_transfer_file_mode_t file_mode=GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY;
  3662. globus_io_secure_authorization_data_t data;
  3663. globus_l_gass_transfer_failed_kickout_closure_t *kickout;
  3664. globus_reltime_t delay_time;
  3665. MYNAME(globus_l_gass_transfer_http_accept);
  3666. debug_printf(1, (_GTSL("entering %s()\n"),myname));
  3667. l_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
  3668. /* Allocate proto instance */
  3669. l_proto->request = (globus_gass_transfer_http_request_proto_t *)
  3670. globus_malloc(sizeof(globus_gass_transfer_http_request_proto_t));
  3671. if(l_proto->request == GLOBUS_NULL)
  3672. {
  3673. goto error_exit;
  3674. }
  3675. result = globus_io_tcpattr_init(&tcp_attr);
  3676. if(result != GLOBUS_SUCCESS)
  3677. {
  3678. goto proto_error;
  3679. }
  3680. globus_io_attr_set_socket_keepalive(&tcp_attr, GLOBUS_TRUE);
  3681. if(attr != GLOBUS_NULL &&
  3682. *attr != GLOBUS_NULL)
  3683. {
  3684. /* Check attributes we care about */
  3685. rc = globus_gass_transfer_requestattr_get_socket_sndbuf(
  3686. attr,
  3687. &sndbuf);
  3688. if(rc != GLOBUS_SUCCESS)
  3689. {
  3690. goto tcpattr_error;
  3691. }
  3692. else
  3693. {
  3694. if(sndbuf != 0)
  3695. {
  3696. globus_io_attr_set_socket_sndbuf(&tcp_attr,
  3697. sndbuf);
  3698. }
  3699. }
  3700. rc = globus_gass_transfer_requestattr_get_socket_rcvbuf(
  3701. attr,
  3702. &rcvbuf);
  3703. if(rc != GLOBUS_SUCCESS)
  3704. {
  3705. goto tcpattr_error;
  3706. }
  3707. else
  3708. {
  3709. if(rcvbuf != 0)
  3710. {
  3711. globus_io_attr_set_socket_rcvbuf(&tcp_attr,
  3712. rcvbuf);
  3713. }
  3714. }
  3715. rc = globus_gass_transfer_requestattr_get_socket_nodelay(
  3716. attr,
  3717. &nodelay);
  3718. if(rc != GLOBUS_SUCCESS)
  3719. {
  3720. goto tcpattr_error;
  3721. }
  3722. else
  3723. {
  3724. globus_io_attr_set_tcp_nodelay(&tcp_attr,
  3725. nodelay);
  3726. }
  3727. /* File mode is important on Windows */
  3728. rc = globus_gass_transfer_requestattr_get_file_mode(attr,
  3729. &file_mode);
  3730. if(rc != GLOBUS_SUCCESS)
  3731. {
  3732. goto tcpattr_error;
  3733. }
  3734. rc = globus_gass_transfer_requestattr_get_block_size(
  3735. attr,
  3736. &l_proto->request->block_size);
  3737. if(rc != GLOBUS_SUCCESS)
  3738. {
  3739. goto tcpattr_error;
  3740. }
  3741. }
  3742. /* If https, set security attributes for the request */
  3743. if(l_proto->url_scheme == GLOBUS_URL_SCHEME_HTTPS)
  3744. {
  3745. globus_result_t result;
  3746. globus_io_secure_authorization_data_initialize(&data);
  3747. result = globus_io_attr_set_secure_authentication_mode(
  3748. &tcp_attr,
  3749. GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
  3750. GLOBUS_NULL);
  3751. if(result != GLOBUS_SUCCESS)
  3752. {
  3753. goto free_auth_data;
  3754. }
  3755. result = globus_io_attr_set_secure_channel_mode(
  3756. &tcp_attr,
  3757. GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
  3758. if(result != GLOBUS_SUCCESS)
  3759. {
  3760. goto free_auth_data;
  3761. }
  3762. if(attr != GLOBUS_NULL)
  3763. {
  3764. if(*attr != GLOBUS_NULL)
  3765. {
  3766. rc = globus_gass_transfer_secure_requestattr_get_authorization(
  3767. attr,
  3768. &l_proto->request->authorization_mode,
  3769. &l_proto->request->authorized_subject);
  3770. if(rc != GLOBUS_SUCCESS)
  3771. {
  3772. goto free_auth_data;
  3773. }
  3774. }
  3775. }
  3776. result = globus_io_secure_authorization_data_set_callback(
  3777. &data,
  3778. globus_l_gass_transfer_http_authorization_callback,
  3779. proto);
  3780. if(result != GLOBUS_SUCCESS)
  3781. {
  3782. goto free_auth_data;
  3783. }
  3784. result = globus_io_attr_set_secure_authorization_mode(
  3785. &tcp_attr,
  3786. GLOBUS_IO_SECURE_AUTHORIZATION_MODE_CALLBACK,
  3787. &data);
  3788. if(result != GLOBUS_SUCCESS)
  3789. {
  3790. goto free_auth_data;
  3791. }
  3792. globus_io_secure_authorization_data_destroy(&data);
  3793. }
  3794. /* Initialize the proto instance */
  3795. l_proto->request->send_buffer= globus_l_gass_transfer_http_send;
  3796. l_proto->request->recv_buffer = globus_l_gass_transfer_http_receive;
  3797. l_proto->request->fail = globus_l_gass_transfer_http_fail;
  3798. l_proto->request->deny = globus_l_gass_transfer_http_request_deny;
  3799. l_proto->request->refer = globus_l_gass_transfer_http_request_refer;
  3800. l_proto->request->authorize = globus_l_gass_transfer_http_request_authorize;
  3801. l_proto->request->destroy = globus_l_gass_transfer_http_destroy;
  3802. l_proto->request->text_mode = (file_mode == GLOBUS_GASS_TRANSFER_FILE_MODE_TEXT);
  3803. l_proto->request->line_mode = GLOBUS_L_LINE_MODE_UNKNOWN;
  3804. l_proto->request->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING;
  3805. l_proto->request->request = request;
  3806. l_proto->request->type = globus_gass_transfer_request_get_type(request);
  3807. l_proto->request->code = 0;
  3808. l_proto->request->reason = 0;
  3809. l_proto->request->parse_error = GLOBUS_FALSE;
  3810. l_proto->request->destroy_called = GLOBUS_FALSE;
  3811. l_proto->request->headers = GLOBUS_NULL;
  3812. l_proto->request->response_buffer = GLOBUS_NULL;
  3813. l_proto->request->length = 0;
  3814. l_proto->request->handled = 0;
  3815. l_proto->request->chunked = GLOBUS_FALSE;
  3816. l_proto->request->chunk_left = 0;
  3817. l_proto->request->failure_occurred = GLOBUS_FALSE;
  3818. l_proto->request->oneshot_registered = GLOBUS_FALSE;
  3819. l_proto->request->oneshot_active = GLOBUS_FALSE;
  3820. l_proto->request->eof_read = GLOBUS_FALSE;
  3821. l_proto->request->method = GLOBUS_NULL;
  3822. l_proto->request->uri = GLOBUS_NULL;
  3823. l_proto->request->response_offset = 0;
  3824. l_proto->request->parsed_offset = 0;
  3825. l_proto->request->client_side = GLOBUS_FALSE;
  3826. l_proto->request->connected_subject = GLOBUS_NULL;
  3827. /* Register accept with new request */
  3828. l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING;
  3829. debug_printf(4,(_GTSL("%s(): Registering accept on %p\n"),
  3830. myname,
  3831. &l_proto->handle));
  3832. result = globus_io_tcp_register_accept(&l_proto->handle,
  3833. &tcp_attr,
  3834. &l_proto->request->handle,
  3835. globus_l_gass_transfer_http_accept_callback,
  3836. l_proto);
  3837. if(result != GLOBUS_SUCCESS)
  3838. {
  3839. goto tcpattr_error;
  3840. }
  3841. globus_io_tcpattr_destroy(&tcp_attr);
  3842. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  3843. return;
  3844. free_auth_data:
  3845. globus_io_secure_authorization_data_destroy(&data);
  3846. tcpattr_error:
  3847. globus_io_tcpattr_destroy(&tcp_attr);
  3848. proto_error:
  3849. globus_l_gass_transfer_http_proto_destroy(l_proto->request);
  3850. l_proto->request = NULL;
  3851. error_exit:
  3852. l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
  3853. globus_l_gass_transfer_http_unlock();
  3854. GlobusTimeReltimeSet(delay_time, 0, 0);
  3855. debug_printf(4,(_GTSL("%s(): Registering oneshot\n"),
  3856. myname));
  3857. kickout = globus_libc_malloc(
  3858. sizeof(globus_l_gass_transfer_failed_kickout_closure_t));
  3859. kickout->l_proto = l_proto;
  3860. kickout->request = request;
  3861. globus_callback_register_oneshot(
  3862. GLOBUS_NULL,
  3863. &delay_time,
  3864. globus_l_gass_transfer_http_accept_failed_kickout,
  3865. kickout);
  3866. debug_printf(1, (_GTSL("exiting %s()\n"),myname));
  3867. }
  3868. /* globus_l_gass_transfer_http_accept() */
  3869. static
  3870. globus_result_t
  3871. globus_l_gass_transfer_http_register_read(
  3872. globus_gass_transfer_http_request_proto_t * proto)
  3873. {
  3874. MYNAME(globus_l_gass_transfer_http_register_read);
  3875. /*
  3876. * If binary, and some chunk data is unread from the handle,
  3877. * or we are not chunked, we can read directly into the user's
  3878. * buffer. Otherwise, we must buffer the data and then copy it
  3879. * to the user's buffer.
  3880. */
  3881. if(proto->text_mode == GLOBUS_FALSE &&
  3882. (
  3883. (proto->chunked &&
  3884. proto->chunk_left > 0 &&
  3885. proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY) ||
  3886. (proto->chunked == GLOBUS_FALSE)
  3887. )
  3888. )
  3889. {
  3890. globus_size_t minimum;
  3891. globus_size_t maximum;
  3892. minimum = proto->user_waitlen;
  3893. if(minimum > proto->user_buflen - proto->user_offset)
  3894. {
  3895. minimum = proto->user_buflen - proto->user_offset;
  3896. }
  3897. if(proto->chunked && minimum > proto->chunk_left)
  3898. {
  3899. minimum = proto->chunk_left;
  3900. }
  3901. if(proto->length != 0 &&
  3902. minimum > proto->length - proto->handled)
  3903. {
  3904. minimum = proto->length - proto->handled;
  3905. }
  3906. maximum = proto->user_buflen - proto->user_offset;
  3907. if(proto->chunked && maximum > proto->chunk_left)
  3908. {
  3909. maximum = proto->chunk_left;
  3910. }
  3911. if(proto->length != 0 &&
  3912. maximum > proto->length - proto->handled)
  3913. {
  3914. maximum = proto->length - proto->handled;
  3915. }
  3916. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  3917. myname,
  3918. &proto->handle));
  3919. return
  3920. globus_io_register_read(&proto->handle,
  3921. proto->user_buffer +
  3922. proto->user_offset,
  3923. maximum,
  3924. minimum,
  3925. globus_l_gass_transfer_http_read_callback,
  3926. proto);
  3927. }
  3928. else
  3929. {
  3930. /*
  3931. * In text mode or in "chunked" mode, we will have
  3932. * to buffer the data and then apply some transformation
  3933. * to it upon receiving it.
  3934. */
  3935. globus_size_t smaller;
  3936. smaller = proto->user_waitlen;
  3937. if (proto->response_buflen - proto->response_offset == 0)
  3938. {
  3939. /* if buffer is full, shift unparsed data to buffer head */
  3940. memmove(proto->response_buffer,
  3941. proto->response_buffer + proto->parsed_offset,
  3942. proto->response_offset - proto->parsed_offset);
  3943. proto->response_offset -= proto->parsed_offset;
  3944. proto->parsed_offset = 0;
  3945. }
  3946. if (proto->response_buflen - proto->response_offset == 0)
  3947. {
  3948. unsigned char * tmp;
  3949. /* buffer still full... resize buffer */
  3950. tmp = realloc(proto->response_buffer, proto->response_buflen * 2);
  3951. if(tmp == GLOBUS_NULL)
  3952. {
  3953. proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
  3954. proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
  3955. return GLOBUS_FAILURE;
  3956. }
  3957. else
  3958. {
  3959. proto->response_buffer = tmp;
  3960. proto->response_buflen *= 2;
  3961. }
  3962. }
  3963. if(smaller > proto->response_buflen - proto->response_offset)
  3964. {
  3965. smaller = proto->response_buflen - proto->response_offset;
  3966. }
  3967. debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
  3968. myname,
  3969. &proto->handle));
  3970. return
  3971. globus_io_register_read(&proto->handle,
  3972. proto->response_buffer +
  3973. proto->response_offset,
  3974. proto->response_buflen -
  3975. proto->response_offset,
  3976. smaller,
  3977. globus_l_gass_transfer_http_read_buffered_callback,
  3978. proto);
  3979. }
  3980. }
  3981. static
  3982. char *
  3983. globus_l_gass_transfer_http_hex_escape(
  3984. const unsigned char * url)
  3985. {
  3986. unsigned char * new_url;
  3987. const unsigned char * tmp_in;
  3988. unsigned char * tmp_out;
  3989. char hex[3];
  3990. new_url = globus_libc_malloc(strlen((char *) url)*3+1);
  3991. if (new_url == NULL)
  3992. {
  3993. return NULL;
  3994. }
  3995. tmp_in = url;
  3996. tmp_out = new_url;
  3997. while ((*tmp_in) != '\0')
  3998. {
  3999. if (isspace(*tmp_in))
  4000. {
  4001. sprintf(hex, "%2x", (unsigned int) *(tmp_in++));
  4002. *(tmp_out++) = '%';
  4003. *(tmp_out++) = hex[0];
  4004. *(tmp_out++) = hex[1];
  4005. }
  4006. else
  4007. {
  4008. *(tmp_out++) = *(tmp_in++);
  4009. }
  4010. }
  4011. *tmp_out = '\0';
  4012. return (char *) new_url;
  4013. }
  4014. /* globus_l_gass_transfer_http_hex_escape() */
  4015. static
  4016. char *
  4017. globus_l_gass_transfer_http_construct_request(
  4018. globus_gass_transfer_http_request_proto_t * proto)
  4019. {
  4020. globus_size_t cmd_len;
  4021. char * cmd = GLOBUS_NULL;
  4022. globus_size_t length;
  4023. char * url = GLOBUS_NULL;
  4024. /* Construct the request string to send to the server */
  4025. cmd_len = 3; /* for CRLF\0 termination */
  4026. cmd_len += strlen(proto->url.host); /* Required for http/1.1*/
  4027. if(proto->proxy_connect)
  4028. {
  4029. url = globus_l_gass_transfer_http_hex_escape((unsigned char *) proto->url_string);
  4030. if (url == NULL)
  4031. {
  4032. return NULL;
  4033. }
  4034. cmd_len += strlen(url);
  4035. }
  4036. else
  4037. {
  4038. url = globus_l_gass_transfer_http_hex_escape((unsigned char *) proto->url.url_path);
  4039. if (url == NULL)
  4040. {
  4041. return NULL;
  4042. }
  4043. cmd_len += strlen(url);
  4044. }
  4045. switch(proto->type)
  4046. {
  4047. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
  4048. cmd_len += strlen(GLOBUS_L_GET_COMMAND);
  4049. cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
  4050. if(cmd == GLOBUS_NULL)
  4051. {
  4052. globus_libc_free(url);
  4053. return GLOBUS_NULL;
  4054. }
  4055. sprintf(cmd,
  4056. GLOBUS_L_GET_COMMAND,
  4057. url,
  4058. proto->url.host);
  4059. strcat(cmd,
  4060. CRLF);
  4061. globus_libc_free(url);
  4062. return cmd;
  4063. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
  4064. cmd_len += strlen(GLOBUS_L_PUT_COMMAND);
  4065. cmd_len += 2;
  4066. if(proto->text_mode == GLOBUS_TRUE)
  4067. {
  4068. cmd_len += strlen(GLOBUS_L_TEXT_HEADER);
  4069. }
  4070. else
  4071. {
  4072. cmd_len += strlen(GLOBUS_L_BINARY_HEADER);
  4073. }
  4074. length = globus_gass_transfer_request_get_length(proto->request);
  4075. if(length != 0)
  4076. {
  4077. globus_size_t x = length;
  4078. globus_size_t digits = 0;
  4079. /* count the number of decimal digits in length */
  4080. do
  4081. {
  4082. digits++;
  4083. x /= 10;
  4084. } while(x > 0);
  4085. cmd_len += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
  4086. cmd_len += digits;
  4087. cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
  4088. if(cmd == GLOBUS_NULL)
  4089. {
  4090. globus_libc_free(url);
  4091. return GLOBUS_NULL;
  4092. }
  4093. sprintf((char *) cmd,
  4094. GLOBUS_L_PUT_COMMAND,
  4095. url,
  4096. proto->url.host);
  4097. sprintf(cmd + strlen(cmd),
  4098. GLOBUS_L_CONTENT_LENGTH_HEADER,
  4099. length);
  4100. }
  4101. else
  4102. {
  4103. cmd_len += strlen(GLOBUS_L_CHUNKED_HEADER);
  4104. cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
  4105. proto->chunked = GLOBUS_TRUE;
  4106. /* hex encoding of globus_size_t: two bytes to encode per 8 bits,
  4107. * plus a CRLF to end the chunk header
  4108. */
  4109. proto->iov[0].iov_base = (void *)
  4110. globus_malloc((sizeof(globus_size_t) * 2) + 2);
  4111. /* This never changes */
  4112. proto->iov[2].iov_base = CRLF;
  4113. proto->iov[2].iov_len = 2;
  4114. proto->iov[3].iov_base = "0" CRLF CRLF;
  4115. proto->iov[3].iov_len = strlen("0" CRLF CRLF);
  4116. if(cmd == GLOBUS_NULL)
  4117. {
  4118. globus_libc_free(url);
  4119. return GLOBUS_NULL;
  4120. }
  4121. sprintf((char *) cmd,
  4122. GLOBUS_L_PUT_COMMAND,
  4123. url,
  4124. proto->url.host);
  4125. strcat(cmd,
  4126. GLOBUS_L_CHUNKED_HEADER);
  4127. }
  4128. if(proto->text_mode)
  4129. {
  4130. strcat(cmd,
  4131. GLOBUS_L_TEXT_HEADER);
  4132. }
  4133. else
  4134. {
  4135. strcat(cmd,
  4136. GLOBUS_L_BINARY_HEADER);
  4137. }
  4138. strcat(cmd,
  4139. CRLF);
  4140. globus_libc_free(url);
  4141. return cmd;
  4142. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
  4143. cmd_len += strlen(GLOBUS_L_APPEND_COMMAND);
  4144. cmd_len += 2;
  4145. if(proto->text_mode == GLOBUS_TRUE)
  4146. {
  4147. cmd_len += strlen(GLOBUS_L_TEXT_HEADER);
  4148. }
  4149. else
  4150. {
  4151. cmd_len += strlen(GLOBUS_L_BINARY_HEADER);
  4152. }
  4153. length = globus_gass_transfer_request_get_length(proto->request);
  4154. if(length != 0)
  4155. {
  4156. globus_size_t x = length;
  4157. globus_size_t digits = 0;
  4158. /* count the number of decimal digits in length */
  4159. do
  4160. {
  4161. digits++;
  4162. x /= 10;
  4163. } while(x > 0);
  4164. cmd_len += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
  4165. cmd_len += digits;
  4166. cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
  4167. if(cmd == GLOBUS_NULL)
  4168. {
  4169. globus_libc_free(url);
  4170. return GLOBUS_NULL;
  4171. }
  4172. sprintf((char *) cmd,
  4173. GLOBUS_L_APPEND_COMMAND,
  4174. url,
  4175. proto->url.host);
  4176. sprintf((char *) cmd + strlen(cmd),
  4177. GLOBUS_L_CONTENT_LENGTH_HEADER,
  4178. length);
  4179. }
  4180. else
  4181. {
  4182. cmd_len += strlen(GLOBUS_L_CHUNKED_HEADER);
  4183. cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
  4184. proto->chunked = GLOBUS_TRUE;
  4185. /* hex encoding of globus_size_t: two bytes to encode per 8 bits,
  4186. * plus a CRLF to end the chunk header
  4187. */
  4188. proto->iov[0].iov_base = (void *)
  4189. globus_malloc((sizeof(globus_size_t) * 2) + 2);
  4190. /* This never changes */
  4191. proto->iov[2].iov_base = CRLF;
  4192. proto->iov[2].iov_len = 2;
  4193. proto->iov[3].iov_base = "0" CRLF CRLF;
  4194. proto->iov[3].iov_len = 5;
  4195. if(cmd == GLOBUS_NULL)
  4196. {
  4197. globus_libc_free(url);
  4198. return GLOBUS_NULL;
  4199. }
  4200. sprintf((char *) cmd,
  4201. GLOBUS_L_APPEND_COMMAND,
  4202. proto->url.url_path,
  4203. proto->url.host);
  4204. strcat(cmd,
  4205. GLOBUS_L_CHUNKED_HEADER);
  4206. }
  4207. if(proto->text_mode)
  4208. {
  4209. strcat(cmd,
  4210. GLOBUS_L_TEXT_HEADER);
  4211. }
  4212. else
  4213. {
  4214. strcat(cmd,
  4215. GLOBUS_L_BINARY_HEADER);
  4216. }
  4217. strcat(cmd,
  4218. CRLF);
  4219. globus_libc_free(url);
  4220. return cmd;
  4221. case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID:
  4222. default:
  4223. globus_assert(proto->type !=
  4224. GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
  4225. globus_assert(GLOBUS_FALSE);
  4226. globus_libc_free(url);
  4227. return GLOBUS_NULL;
  4228. }
  4229. }
  4230. #endif /* !parser only */
  4231. /*
  4232. * Function: globus_l_gass_transfer_http_parse_response()
  4233. *
  4234. * Description: Parse a byte array containing a (maybe)
  4235. * partial response from the server.
  4236. *
  4237. * Parameters: Protocol module this pertains to
  4238. *
  4239. * Returns: GLOBUS_TRUE if more headers must be read.
  4240. *
  4241. */
  4242. static
  4243. globus_bool_t
  4244. globus_l_gass_transfer_http_parse_response(
  4245. globus_gass_transfer_http_request_proto_t * proto)
  4246. {
  4247. /*
  4248. * Parse the HTTP Response
  4249. *
  4250. * Grammar (from RFC 2068)
  4251. *
  4252. * Response = Status-Line ; Section 6.1
  4253. * *( general-header ; Section 4.5
  4254. * | response-header ; Section 6.2
  4255. * | entity-header ) ; Section 7.1
  4256. * CRLF
  4257. * [ message-body ] ; Section 7.2
  4258. */
  4259. if(proto->reason == GLOBUS_NULL)
  4260. {
  4261. if(globus_l_gass_transfer_http_parse_status_line(proto))
  4262. {
  4263. goto repost_read;
  4264. }
  4265. else if(proto->parse_error)
  4266. {
  4267. goto parse_error;
  4268. }
  4269. }
  4270. if(globus_l_gass_transfer_http_parse_headers(proto))
  4271. {
  4272. goto repost_read;
  4273. }
  4274. else if(proto->parse_error)
  4275. {
  4276. goto parse_error;
  4277. }
  4278. return GLOBUS_FALSE;
  4279. repost_read:
  4280. return GLOBUS_TRUE;
  4281. parse_error:
  4282. return GLOBUS_FALSE;
  4283. }
  4284. /* globus_l_gass_transfer_http_parse_response() */
  4285. static
  4286. globus_bool_t
  4287. globus_l_gass_transfer_http_parse_request(
  4288. globus_gass_transfer_http_request_proto_t * proto)
  4289. {
  4290. /*
  4291. * Parse the HTTP Request
  4292. *
  4293. * Request = Request-Line ; Section 5.1
  4294. * *( general-header ; Section 4.5
  4295. * | request-header ; Section 5.3
  4296. * | entity-header ) ; Section 7.1
  4297. * CRLF
  4298. * [ message-body ] ; Section 7.2
  4299. *
  4300. */
  4301. if(proto->method == GLOBUS_NULL)
  4302. {
  4303. if(globus_l_gass_transfer_http_parse_request_line(proto))
  4304. {
  4305. goto repost_read;
  4306. }
  4307. else if(proto->parse_error)
  4308. {
  4309. goto parse_error;
  4310. }
  4311. }
  4312. if(globus_l_gass_transfer_http_parse_headers(proto))
  4313. {
  4314. goto repost_read;
  4315. }
  4316. else if(proto->parse_error)
  4317. {
  4318. goto parse_error;
  4319. }
  4320. return GLOBUS_FALSE;
  4321. repost_read:
  4322. return GLOBUS_TRUE;
  4323. parse_error:
  4324. return GLOBUS_FALSE;
  4325. }
  4326. /* globus_l_gass_transfer_http_parse_request() */
  4327. static
  4328. globus_bool_t
  4329. globus_l_gass_transfer_http_parse_status_line(
  4330. globus_gass_transfer_http_request_proto_t * proto)
  4331. {
  4332. globus_size_t offset;
  4333. globus_size_t reason_offset;
  4334. int r_offset;
  4335. offset = 0;
  4336. /*
  4337. * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
  4338. * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
  4339. */
  4340. if(!globus_l_gass_transfer_http_find_crlf(
  4341. proto->response_buffer + proto->parsed_offset,
  4342. proto->response_offset - proto->parsed_offset,
  4343. &offset))
  4344. {
  4345. return GLOBUS_TRUE;
  4346. }
  4347. /* Replace CRLF with NULL */
  4348. proto->response_buffer[proto->parsed_offset + offset] = '\0';
  4349. if(sscanf((char *) proto->response_buffer + proto->parsed_offset,
  4350. "HTTP/%d.%d %d %n",
  4351. &proto->major,
  4352. &proto->minor,
  4353. &proto->code,
  4354. &r_offset) != 3)
  4355. {
  4356. /* Not a HTTP response */
  4357. if(proto->code == 0)
  4358. {
  4359. proto->code =
  4360. GLOBUS_L_PROTOCOL_FAILURE_CODE;
  4361. proto->reason =
  4362. globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
  4363. }
  4364. proto->parsed_offset += offset;
  4365. /* skip the CRLF, as well */
  4366. proto->parsed_offset+=2;
  4367. goto parse_error;
  4368. }
  4369. reason_offset = (globus_size_t) r_offset;
  4370. proto->reason = globus_libc_strdup((char *) (proto->response_buffer +
  4371. proto->parsed_offset +
  4372. reason_offset));
  4373. proto->parsed_offset += offset;
  4374. /* skip the CRLF, as well */
  4375. proto->parsed_offset+=2;
  4376. return GLOBUS_FALSE;
  4377. parse_error:
  4378. proto->parse_error = GLOBUS_TRUE;
  4379. return GLOBUS_FALSE;
  4380. }
  4381. static
  4382. globus_bool_t
  4383. globus_l_gass_transfer_http_parse_request_line(
  4384. globus_gass_transfer_http_request_proto_t * proto)
  4385. {
  4386. globus_size_t offset;
  4387. offset = 0;
  4388. /*
  4389. * Request-Line = Method SP Request-URI SP HTTP-Version CRLF
  4390. * Method = "OPTIONS" ; Section 9.2
  4391. * | "GET" ; Section 9.3
  4392. * | "HEAD" ; Section 9.4
  4393. * | "POST" ; Section 9.5
  4394. * | "PUT" ; Section 9.6
  4395. * | "DELETE" ; Section 9.7
  4396. * | "TRACE" ; Section 9.8
  4397. * | extension-method
  4398. *
  4399. * extension-method = token
  4400. */
  4401. if(!globus_l_gass_transfer_http_find_crlf(
  4402. proto->response_buffer + proto->parsed_offset,
  4403. proto->response_offset - proto->parsed_offset,
  4404. &offset))
  4405. {
  4406. return GLOBUS_TRUE;
  4407. }
  4408. /* Replace CRLF with NULL */
  4409. proto->response_buffer[proto->parsed_offset + offset] = '\0';
  4410. proto->method = globus_malloc(offset);
  4411. proto->uri = globus_malloc(offset);
  4412. if(sscanf((char *) proto->response_buffer + proto->parsed_offset,
  4413. "%s %s HTTP/%d.%d",
  4414. proto->method,
  4415. proto->uri,
  4416. &proto->major,
  4417. &proto->minor) != 4)
  4418. {
  4419. /* Not a HTTP request */
  4420. if(proto->code == 0)
  4421. {
  4422. proto->code =
  4423. GLOBUS_L_PROTOCOL_FAILURE_CODE;
  4424. proto->reason =
  4425. globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
  4426. }
  4427. proto->parsed_offset += offset;
  4428. /* skip the CRLF, as well */
  4429. proto->parsed_offset+=2;
  4430. goto parse_error;
  4431. }
  4432. /* skip the CRLF, as well */
  4433. proto->parsed_offset += offset + 2;
  4434. return GLOBUS_FALSE;
  4435. parse_error:
  4436. proto->parse_error = GLOBUS_TRUE;
  4437. return GLOBUS_FALSE;
  4438. }
  4439. static
  4440. globus_bool_t
  4441. globus_l_gass_transfer_http_parse_headers(
  4442. globus_gass_transfer_http_request_proto_t * proto)
  4443. {
  4444. globus_bool_t all_headers = GLOBUS_FALSE;
  4445. while(!all_headers)
  4446. {
  4447. if(globus_l_gass_transfer_http_parse_one_header(proto,
  4448. &all_headers))
  4449. {
  4450. return GLOBUS_TRUE;
  4451. }
  4452. else if(proto->parse_error)
  4453. {
  4454. return GLOBUS_FALSE;
  4455. }
  4456. }
  4457. return GLOBUS_FALSE;
  4458. }
  4459. /* globus_l_gass_transfer_http_parse_headers() */
  4460. static
  4461. globus_bool_t
  4462. globus_l_gass_transfer_http_parse_one_header(
  4463. globus_gass_transfer_http_request_proto_t * proto,
  4464. globus_bool_t * last_header)
  4465. {
  4466. globus_size_t offset;
  4467. globus_bool_t end_of_header;
  4468. globus_size_t continuation=0;
  4469. char * value;
  4470. char * new_value;
  4471. int i;
  4472. /*
  4473. * message-header = field-name ":" [ field-value ] CRLF
  4474. *
  4475. * field-name = token
  4476. * field-value = *( field-content | LWS )
  4477. * LWS = [CRLF] 1*( SP | HT )
  4478. *
  4479. * field-content = <the OCTETs making up the field-value
  4480. * and consisting of either *TEXT or combinations
  4481. * of token, tspecials, and quoted-string>
  4482. * token = 1*<any CHAR except CTLs or tspecials>
  4483. * CTL = <any US-ASCII control character
  4484. * (octets 0 - 31) and DEL (127)>
  4485. * tspecials = "(" | ")" | "<" | ">" | "@"
  4486. * | "," | ";" | ":" | "\" | <">
  4487. * | "/" | "[" | "]" | "?" | "="
  4488. * | "{" | "}" | SP | HT
  4489. *
  4490. * This implementation is a little lax on the character restrictions...
  4491. */
  4492. end_of_header = GLOBUS_FALSE;
  4493. /* Find the complete header (which may span multiple lines) */
  4494. while(!end_of_header)
  4495. {
  4496. /* Find the end of this header line */
  4497. if(! globus_l_gass_transfer_http_find_crlf(
  4498. proto->response_buffer +
  4499. proto->parsed_offset +
  4500. continuation,
  4501. proto->response_offset -
  4502. proto->parsed_offset -
  4503. continuation,
  4504. &offset))
  4505. {
  4506. return GLOBUS_TRUE;
  4507. }
  4508. else if(offset == 0)
  4509. {
  4510. end_of_header = GLOBUS_TRUE;
  4511. break;
  4512. }
  4513. /*
  4514. * Reached end-of-read data before being able to detect a
  4515. * continuation
  4516. */
  4517. if(proto->parsed_offset + continuation + offset + 2 >=
  4518. proto->response_offset)
  4519. {
  4520. return GLOBUS_TRUE;
  4521. }
  4522. /* Check for continuation (LWS) */
  4523. if(islws(proto->response_buffer[proto->parsed_offset +
  4524. continuation + offset + 2]))
  4525. {
  4526. continuation += offset + 2;
  4527. }
  4528. else
  4529. {
  4530. /* No continuation, we have a header */
  4531. end_of_header = GLOBUS_TRUE;
  4532. }
  4533. }
  4534. /* This is the last header if it consists of CRLF only */
  4535. if(proto->response_buffer[proto->parsed_offset] == CR &&
  4536. proto->response_buffer[proto->parsed_offset + 1] == LF &&
  4537. continuation + offset == 0)
  4538. {
  4539. *last_header = GLOBUS_TRUE;
  4540. proto->parsed_offset += 2;
  4541. return GLOBUS_FALSE;
  4542. }
  4543. /* Canonical form of header is lower-case */
  4544. for(i = proto->parsed_offset; i < proto->parsed_offset + continuation + offset; i++)
  4545. {
  4546. if(proto->response_buffer[i] == ':')
  4547. {
  4548. break;
  4549. }
  4550. else
  4551. {
  4552. proto->response_buffer[i] =
  4553. (char) tolower((int) (proto->response_buffer[i]));
  4554. }
  4555. }
  4556. if(proto->response_buffer[i] != ':')
  4557. {
  4558. /* The header's name is illegal */
  4559. proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
  4560. if(proto->reason != GLOBUS_NULL)
  4561. {
  4562. globus_free(proto->reason);
  4563. }
  4564. proto->reason =
  4565. globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
  4566. proto->parse_error = GLOBUS_TRUE;
  4567. return GLOBUS_FALSE;
  4568. }
  4569. /* NULL-terminate the header's name */
  4570. proto->response_buffer[i] = '\0';
  4571. new_value = (char *) &proto->response_buffer[i+1];
  4572. /* Make the header's value NULL terminated */
  4573. proto->response_buffer[proto->parsed_offset+continuation+offset] = '\0';
  4574. /*
  4575. * Add header to table. If it already there, append a
  4576. * comma and the new header's value.
  4577. */
  4578. value = (char *) globus_i_gass_transfer_keyvalue_lookup(
  4579. &proto->headers,
  4580. (char *) (proto->response_buffer + proto->parsed_offset));
  4581. if(value == GLOBUS_NULL)
  4582. {
  4583. /* New header */
  4584. globus_i_gass_transfer_keyvalue_insert(
  4585. &proto->headers,
  4586. globus_libc_strdup((char *) (proto->response_buffer +
  4587. proto->parsed_offset)),
  4588. globus_libc_strdup(new_value));
  4589. }
  4590. else
  4591. {
  4592. /* Existing header, append */
  4593. globus_byte_t * new_ptr;
  4594. new_ptr = globus_libc_realloc(value,
  4595. (strlen(value) +
  4596. strlen(new_value) + 2) *
  4597. sizeof(globus_byte_t));
  4598. strcat((char *) new_ptr,
  4599. ",");
  4600. strcat((char *) new_ptr,
  4601. new_value);
  4602. globus_i_gass_transfer_keyvalue_replace(
  4603. &proto->headers,
  4604. (char *) (proto->response_buffer + proto->parsed_offset),
  4605. (char *) new_ptr);
  4606. }
  4607. /* Move the "parsed" pointer to the end of what we've just handled */
  4608. proto->parsed_offset += continuation + offset + 2;
  4609. return GLOBUS_FALSE;
  4610. }
  4611. /* globus_l_gass_transfer_http_parse_one_header() */
  4612. static
  4613. globus_bool_t
  4614. globus_l_gass_transfer_http_find_crlf(
  4615. globus_byte_t * bytes,
  4616. globus_size_t len,
  4617. globus_size_t * crlf_offset)
  4618. {
  4619. int i;
  4620. if(len == 0)
  4621. {
  4622. return GLOBUS_FALSE;
  4623. }
  4624. /* See if we can find the end an http meta-information line */
  4625. for (i = 0; i < len-1; i++)
  4626. {
  4627. if(bytes[i] == CR &&
  4628. bytes[i+1] == LF)
  4629. {
  4630. *crlf_offset = i;
  4631. return GLOBUS_TRUE;
  4632. }
  4633. }
  4634. return GLOBUS_FALSE;
  4635. }
  4636. /* globus_l_gass_transfer_http_find_crlf() */
  4637. /*
  4638. * Function: globus_l_gass_transfer_http_copy_text_buffer()
  4639. *
  4640. * Description: Copy a text array from an HTTP-message to
  4641. * a user's buffer, converting end-of-line characters
  4642. * to the local host format. Determines the message
  4643. * line format based on the first end-of-line it
  4644. * reaches if it is unknown.
  4645. *
  4646. * Parameters:
  4647. *
  4648. * Returns:
  4649. */
  4650. void
  4651. globus_l_gass_transfer_http_copy_text_buffer(
  4652. globus_byte_t * output,
  4653. globus_byte_t * input,
  4654. globus_gass_transfer_http_line_mode_t * line_mode,
  4655. globus_size_t max_input,
  4656. globus_size_t max_output,
  4657. globus_size_t * input_copied,
  4658. globus_size_t * output_copied)
  4659. {
  4660. globus_size_t src;
  4661. globus_size_t dst;
  4662. src = 0;
  4663. dst = 0;
  4664. /* Need to determine the line terminator */
  4665. if(*line_mode == GLOBUS_L_LINE_MODE_UNKNOWN)
  4666. {
  4667. while(src < max_input-1 && dst < max_output-1)
  4668. {
  4669. if(input[src] == CR && (*line_mode) ==
  4670. GLOBUS_L_LINE_MODE_UNKNOWN)
  4671. {
  4672. if(input[src+1] == LF)
  4673. {
  4674. *line_mode = GLOBUS_L_LINE_MODE_CRLF;
  4675. break;
  4676. }
  4677. else
  4678. {
  4679. *line_mode = GLOBUS_L_LINE_MODE_CR;
  4680. break;
  4681. }
  4682. }
  4683. else if(input[src] == LF && (*line_mode) ==
  4684. GLOBUS_L_LINE_MODE_UNKNOWN)
  4685. {
  4686. *line_mode = GLOBUS_L_LINE_MODE_LF;
  4687. break;
  4688. }
  4689. else
  4690. {
  4691. output[dst] = GLOBUS_L_TEXT_BYTE(input[src]);
  4692. dst++;
  4693. src++;
  4694. continue;
  4695. }
  4696. }
  4697. /* did we finish because we read the end-of-input or output? */
  4698. if(src == max_input-1 ||
  4699. dst == max_output-1)
  4700. {
  4701. *input_copied = src;
  4702. *output_copied = dst;
  4703. return;
  4704. }
  4705. }
  4706. /*
  4707. * Convert from *line_mode terminated text, to the local-machine's line
  4708. * mode
  4709. */
  4710. while(src < max_input && dst < max_output)
  4711. {
  4712. if(input[src] == CR && input[src+1] == LF &&
  4713. *line_mode == GLOBUS_L_LINE_MODE_CRLF)
  4714. {
  4715. switch(globus_l_gass_transfer_http_line_mode)
  4716. {
  4717. case GLOBUS_L_LINE_MODE_CR:
  4718. /* CRLF to CR */
  4719. output[dst] = CR;
  4720. dst++;
  4721. src += 2;
  4722. break;
  4723. case GLOBUS_L_LINE_MODE_CRLF:
  4724. /* CRLF to CRLF */
  4725. output[dst]= CR;
  4726. dst++;
  4727. output[dst]= LF;
  4728. dst++;
  4729. src += 2;
  4730. break;
  4731. case GLOBUS_L_LINE_MODE_LF:
  4732. /* CRLF to LF */
  4733. output[dst]= LF;
  4734. dst++;
  4735. src += 2;
  4736. break;
  4737. case GLOBUS_L_LINE_MODE_UNKNOWN:
  4738. globus_assert(globus_l_gass_transfer_http_line_mode !=
  4739. GLOBUS_L_LINE_MODE_UNKNOWN);
  4740. }
  4741. }
  4742. else if(input[src] == CR && *line_mode == GLOBUS_L_LINE_MODE_CR)
  4743. {
  4744. switch(globus_l_gass_transfer_http_line_mode)
  4745. {
  4746. case GLOBUS_L_LINE_MODE_CR:
  4747. /* CR to CR */
  4748. output[dst] = CR;
  4749. dst++;
  4750. src++;
  4751. break;
  4752. case GLOBUS_L_LINE_MODE_CRLF:
  4753. /* CR to CRLF */
  4754. output[dst]= CR;
  4755. dst++;
  4756. output[dst]= LF;
  4757. dst++;
  4758. src++;
  4759. break;
  4760. case GLOBUS_L_LINE_MODE_LF:
  4761. /* CRLF to LF */
  4762. output[dst]= LF;
  4763. dst++;
  4764. src++;
  4765. break;
  4766. case GLOBUS_L_LINE_MODE_UNKNOWN:
  4767. globus_assert(globus_l_gass_transfer_http_line_mode !=
  4768. GLOBUS_L_LINE_MODE_UNKNOWN);
  4769. }
  4770. }
  4771. else if(input[src] == LF && *line_mode == GLOBUS_L_LINE_MODE_LF)
  4772. {
  4773. switch(globus_l_gass_transfer_http_line_mode)
  4774. {
  4775. case GLOBUS_L_LINE_MODE_CR:
  4776. /* LF to CR */
  4777. output[dst] = CR;
  4778. dst++;
  4779. src++;
  4780. break;
  4781. case GLOBUS_L_LINE_MODE_CRLF:
  4782. /* LF to CRLF */
  4783. output[dst]= CR;
  4784. dst++;
  4785. output[dst]= LF;
  4786. dst++;
  4787. src++;
  4788. break;
  4789. case GLOBUS_L_LINE_MODE_LF:
  4790. /* LF to LF */
  4791. output[dst]= LF;
  4792. dst++;
  4793. src++;
  4794. break;
  4795. case GLOBUS_L_LINE_MODE_UNKNOWN:
  4796. globus_assert(globus_l_gass_transfer_http_line_mode !=
  4797. GLOBUS_L_LINE_MODE_UNKNOWN);
  4798. }
  4799. }
  4800. else
  4801. {
  4802. output[dst] = GLOBUS_L_TEXT_BYTE(input[src]);
  4803. dst++;
  4804. src++;
  4805. continue;
  4806. }
  4807. }
  4808. *input_copied = src;
  4809. *output_copied = dst;
  4810. }
  4811. /* globus_l_gass_transfer_http_copy_text_buffer() */
  4812. static
  4813. void
  4814. globus_l_gass_transfer_unbuffer_text(
  4815. globus_gass_transfer_http_request_proto_t * proto)
  4816. {
  4817. /*
  4818. * Copy the text from the proto's response buffer to the
  4819. * user's buffer
  4820. */
  4821. globus_size_t input_copied;
  4822. globus_size_t output_copied;
  4823. globus_size_t src_max;
  4824. globus_bool_t redo = GLOBUS_FALSE;
  4825. do
  4826. {
  4827. src_max = proto->response_offset - proto->parsed_offset;
  4828. if(proto->chunked &&
  4829. (src_max > proto->chunk_left))
  4830. {
  4831. src_max = proto->chunk_left;
  4832. }
  4833. /*
  4834. * Copy the text, converting to 7-bit US-ASCII, and
  4835. * converting the document's end-of-line to be the local
  4836. * machine's end-of-line character
  4837. */
  4838. globus_l_gass_transfer_http_copy_text_buffer(
  4839. proto->user_buffer + proto->user_offset,
  4840. proto->response_buffer + proto->parsed_offset,
  4841. &proto->line_mode,
  4842. src_max,
  4843. proto->user_buflen - proto->user_offset,
  4844. &input_copied,
  4845. &output_copied);
  4846. proto->user_offset += output_copied;
  4847. proto->parsed_offset += input_copied;
  4848. proto->handled += input_copied;
  4849. if(proto->chunked)
  4850. {
  4851. proto->chunk_left -= input_copied;
  4852. }
  4853. if(output_copied > proto->user_waitlen)
  4854. {
  4855. proto->user_waitlen = 0;
  4856. }
  4857. else
  4858. {
  4859. proto->user_waitlen -= output_copied;
  4860. }
  4861. if(proto->response_offset - proto->parsed_offset == 1 &&
  4862. proto->line_mode == GLOBUS_L_LINE_MODE_UNKNOWN)
  4863. {
  4864. if(proto->response_buffer[proto->parsed_offset] == CR)
  4865. {
  4866. proto->line_mode = GLOBUS_L_LINE_MODE_CR;
  4867. redo = GLOBUS_TRUE;
  4868. }
  4869. else if (proto->response_buffer[proto->parsed_offset] == LF)
  4870. {
  4871. proto->line_mode = GLOBUS_L_LINE_MODE_LF;
  4872. redo = GLOBUS_TRUE;
  4873. }
  4874. else
  4875. {
  4876. /* doesn't matter, since the document contains no newlines */
  4877. proto->line_mode = GLOBUS_L_LINE_MODE_LF;
  4878. redo = GLOBUS_TRUE;
  4879. }
  4880. }
  4881. else
  4882. {
  4883. redo = GLOBUS_FALSE;
  4884. }
  4885. } while(redo);
  4886. /* Reset our buffer, if we've read it all */
  4887. if(proto->parsed_offset == proto->response_offset)
  4888. {
  4889. proto->parsed_offset = 0;
  4890. proto->response_offset = 0;
  4891. }
  4892. else if(proto->parsed_offset != 0)
  4893. {
  4894. /* This may not be necessary */
  4895. memmove(proto->response_buffer,
  4896. proto->response_buffer + proto->parsed_offset,
  4897. proto->response_offset - proto->parsed_offset);
  4898. proto->response_offset -= proto->parsed_offset;
  4899. proto->parsed_offset = 0;
  4900. }
  4901. }
  4902. /* globus_l_gass_transfer_unbuffer_text() */
  4903. static
  4904. void
  4905. globus_l_gass_transfer_unbuffer_binary(
  4906. globus_gass_transfer_http_request_proto_t * proto)
  4907. {
  4908. /*
  4909. * Copy the binary from the proto's response buffer to the
  4910. * user's buffer
  4911. */
  4912. globus_size_t smaller;
  4913. smaller = proto->response_offset - proto->parsed_offset;
  4914. if(smaller > proto->user_buflen - proto->user_offset)
  4915. {
  4916. smaller = proto->user_buflen - proto->user_offset;
  4917. }
  4918. if(proto->chunked &&
  4919. smaller > proto->chunk_left)
  4920. {
  4921. smaller = proto->chunk_left;
  4922. }
  4923. memcpy(proto->user_buffer + proto->user_offset,
  4924. proto->response_buffer + proto->parsed_offset,
  4925. smaller);
  4926. proto->user_offset += smaller;
  4927. proto->parsed_offset += smaller;
  4928. proto->handled += smaller;
  4929. if(proto->chunked)
  4930. {
  4931. proto->chunk_left -= smaller;
  4932. }
  4933. if(smaller > proto->user_waitlen)
  4934. {
  4935. proto->user_waitlen = 0;
  4936. }
  4937. else
  4938. {
  4939. proto->user_waitlen -= smaller;
  4940. }
  4941. /* Reset our buffer, if we've read it all */
  4942. if(proto->parsed_offset == proto->response_offset)
  4943. {
  4944. proto->parsed_offset = 0;
  4945. proto->response_offset = 0;
  4946. }
  4947. else if(proto->parsed_offset != 0)
  4948. {
  4949. /* This may not be necessary */
  4950. memmove(proto->response_buffer,
  4951. proto->response_buffer + proto->parsed_offset,
  4952. proto->response_offset - proto->parsed_offset);
  4953. proto->response_offset -= proto->parsed_offset;
  4954. proto->parsed_offset = 0;
  4955. }
  4956. }
  4957. /* globus_l_gass_transfer_unbuffer_binary() */
  4958. /* Code for parsing HTTP responses */
  4959. static
  4960. globus_bool_t
  4961. islws(
  4962. char byte)
  4963. {
  4964. return(byte == ' ' ||
  4965. byte == '\t');
  4966. }
  4967. /* islws() */
  4968. static
  4969. globus_bool_t
  4970. ischar(
  4971. char byte)
  4972. {
  4973. return( (unsigned char) byte <= 127 );
  4974. }
  4975. /* ischar() */
  4976. static
  4977. globus_bool_t
  4978. istspecial(
  4979. char byte)
  4980. {
  4981. return (byte == '(' || byte == ')' || byte == '<' ||
  4982. byte == '>' || byte == '@' || byte == ',' ||
  4983. byte == ';' || byte == ':' || byte == '\\' ||
  4984. byte == '"' || byte == '/' || byte == '[' ||
  4985. byte == ']' || byte == '?' || byte == '=' ||
  4986. byte == '{' || byte == '}' || byte == ' ' ||
  4987. byte == '\t');
  4988. }
  4989. /* istspecial() */
  4990. globus_bool_t
  4991. isctl(
  4992. char byte)
  4993. {
  4994. return ((byte >= (char) 0 && byte <= (char) 31) ||
  4995. byte == (char) 127);
  4996. }
  4997. static
  4998. globus_bool_t
  4999. ishex(
  5000. char byte)
  5001. {
  5002. return (byte == 'A' || byte == 'B' || byte == 'C' ||
  5003. byte == 'D' || byte == 'E' || byte == 'F' ||
  5004. byte == 'a' || byte == 'b' || byte == 'c' ||
  5005. byte == 'd' || byte == 'e' || byte == 'f' ||
  5006. byte == '0' || byte == '1' || byte == '2' ||
  5007. byte == '3' || byte == '4' || byte == '5' ||
  5008. byte == '6' || byte == '7' || byte == '8' ||
  5009. byte == '9');
  5010. }
  5011. /*
  5012. * all scan and parse functions return GLOBUS_TRUE if more data
  5013. * is needed to read a complete token
  5014. */
  5015. static
  5016. globus_bool_t
  5017. globus_l_gass_transfer_http_scan_star_lws(
  5018. globus_byte_t * input,
  5019. globus_size_t max_to_scan,
  5020. globus_size_t * end_of_token)
  5021. {
  5022. globus_size_t i;
  5023. *end_of_token = 0;
  5024. /*
  5025. * an interesting note from the HTTP/1.1 RFC
  5026. * implied *LWS
  5027. * The grammar described by this specification is word-based. Except
  5028. * where noted otherwise, linear whitespace (LWS) can be included
  5029. * between any two adjacent words (token or quoted-string), and
  5030. * between adjacent tokens and delimiters (tspecials), without
  5031. * changing the interpretation of a field. At least one delimiter
  5032. * (tspecials) must exist between any two tokens, since they would
  5033. * otherwise be interpreted as a single token.
  5034. *
  5035. * And the definition of the LWS that we are parsing
  5036. *
  5037. * LWS = [CRLF] 1 *(SP | HT)
  5038. * CRLF = CR LF
  5039. * CR = <US-ASCII CR, carriage return (13)>
  5040. * LF = <US-ASCII LF, linefeed (10)>
  5041. * SP = <US-ASCII SP, space (32)>
  5042. * HT = <US-ASCII HT, horizontal-tab (9)>
  5043. */
  5044. for(i = 0; i < max_to_scan; i++)
  5045. {
  5046. if(input[i] == ' ' || input[i] == '\t')
  5047. {
  5048. continue;
  5049. }
  5050. if(input[i] == CR)
  5051. {
  5052. if(i + 2 >= max_to_scan)
  5053. {
  5054. /* not enough data */
  5055. return GLOBUS_TRUE;
  5056. }
  5057. else
  5058. {
  5059. if(input[i+1] == LF &&
  5060. (input[i+2] == ' ' ||
  5061. input[i+2] == '\t'))
  5062. {
  5063. /* pass over LF */
  5064. i++;
  5065. continue;
  5066. }
  5067. else
  5068. {
  5069. /* This CR doesn't match our pattern */
  5070. if(i != 0)
  5071. {
  5072. /* If we've swallowed any whitespace, note it */
  5073. *end_of_token = i;
  5074. }
  5075. return GLOBUS_FALSE;
  5076. }
  5077. }
  5078. }
  5079. else
  5080. {
  5081. /* end of match */
  5082. if(i != 0)
  5083. {
  5084. *end_of_token = i;
  5085. }
  5086. return GLOBUS_FALSE;
  5087. }
  5088. }
  5089. /*
  5090. * If we haven't hit an end of the LWS by the end of input,
  5091. * our (*LWS) can't be greedy, so we need more input
  5092. */
  5093. return GLOBUS_TRUE;
  5094. }
  5095. /* globus_l_gass_transfer_http_scan_star_lws() */
  5096. static
  5097. globus_bool_t
  5098. globus_l_gass_transfer_http_scan_token(
  5099. globus_byte_t * input,
  5100. globus_size_t max_to_scan,
  5101. globus_size_t * end_of_token)
  5102. {
  5103. globus_size_t i;
  5104. *end_of_token = 0;
  5105. /*
  5106. * token = 1*<any CHAR except CTLs or tspecials>
  5107. * CTL = <any US-ASCII control character
  5108. * (octets 0 - 31) and DEL (127)>
  5109. * tspecials = "(" | ")" | "<" | ">" | "@"
  5110. * | "," | ";" | ":" | "\" | <">
  5111. * | "/" | "[" | "]" | "?" | "="
  5112. * | "{" | "}" | SP | HT
  5113. */
  5114. for(i = 0; i < max_to_scan; i++)
  5115. {
  5116. if(!ischar(input[i]) ||
  5117. isctl(input[i]) ||
  5118. istspecial(input[i]))
  5119. {
  5120. if(i != 0)
  5121. {
  5122. *end_of_token = i;
  5123. }
  5124. return GLOBUS_FALSE;
  5125. }
  5126. }
  5127. return GLOBUS_TRUE; /* need more data */
  5128. }
  5129. /* globus_l_gass_transfer_http_scan_token() */
  5130. static
  5131. globus_bool_t
  5132. globus_l_gass_transfer_http_scan_qdtext(
  5133. globus_byte_t * input,
  5134. globus_size_t max_to_scan,
  5135. globus_size_t * end_of_qdtext)
  5136. {
  5137. globus_size_t i;
  5138. globus_size_t j;
  5139. /*
  5140. * qdtext = <any TEXT except <">>
  5141. * TEXT = <any OCTET except CTLs,
  5142. * but including LWS>
  5143. * quoted-pair = "\" CHAR
  5144. * CHAR = <any US-ASCII character (octets 0 - 127)>
  5145. */
  5146. *end_of_qdtext = 0;
  5147. for(i = 0; i < max_to_scan; i++)
  5148. {
  5149. /* Always absorb LWS in quotes */
  5150. if(globus_l_gass_transfer_http_scan_star_lws(
  5151. input + i,
  5152. max_to_scan - i,
  5153. &j))
  5154. {
  5155. return GLOBUS_TRUE; /* need more to scan */
  5156. }
  5157. else if(j != 0)
  5158. {
  5159. i += j; /* scanned some LWS */
  5160. continue;
  5161. }
  5162. else if(input[i] == '\\')
  5163. {
  5164. /* absorb quoted-pair */
  5165. if(i + 1 < max_to_scan)
  5166. {
  5167. if(ischar(input[i+1]))
  5168. {
  5169. i++;
  5170. continue;
  5171. }
  5172. else
  5173. {
  5174. *end_of_qdtext = i;
  5175. return GLOBUS_FALSE;
  5176. }
  5177. }
  5178. else
  5179. {
  5180. return GLOBUS_TRUE; /* need more to scan */
  5181. }
  5182. }
  5183. else if(!isctl(input[i]))
  5184. {
  5185. continue;
  5186. }
  5187. else if(i != 0)
  5188. {
  5189. *end_of_qdtext = i;
  5190. return GLOBUS_FALSE;
  5191. }
  5192. else
  5193. {
  5194. return GLOBUS_FALSE;
  5195. }
  5196. }
  5197. return GLOBUS_TRUE;
  5198. }
  5199. /* globus_l_gass_transfer_http_scan_qdtext() */
  5200. static
  5201. globus_bool_t
  5202. globus_l_gass_transfer_http_scan_quoted_string(
  5203. globus_byte_t * input,
  5204. globus_size_t max_to_scan,
  5205. globus_size_t * end_of_qtd_string)
  5206. {
  5207. globus_size_t i;
  5208. /*
  5209. * quoted-string = ( <"> *(qdtext) <"> )
  5210. */
  5211. *end_of_qtd_string = 0;
  5212. if(max_to_scan == 0)
  5213. {
  5214. return GLOBUS_TRUE;
  5215. }
  5216. /* quoted text must begin with '"' */
  5217. if(input[0] != '"')
  5218. {
  5219. return GLOBUS_FALSE;
  5220. }
  5221. if(globus_l_gass_transfer_http_scan_qdtext(
  5222. input+1,
  5223. max_to_scan-1,
  5224. &i))
  5225. {
  5226. return GLOBUS_TRUE; /* need more data */
  5227. }
  5228. if(i == max_to_scan - 1)
  5229. {
  5230. return GLOBUS_TRUE; /* need more data */
  5231. }
  5232. /* quoted text must end with '"' */
  5233. if(input[i] == '"')
  5234. {
  5235. *end_of_qtd_string = i+1;
  5236. return GLOBUS_FALSE;
  5237. }
  5238. else
  5239. {
  5240. return GLOBUS_FALSE;
  5241. }
  5242. }
  5243. /* globus_l_gass_transfer_http_scan_quoted_string() */
  5244. static
  5245. globus_bool_t
  5246. globus_l_gass_transfer_http_scan_chunk_ext(
  5247. globus_byte_t * input,
  5248. globus_size_t max_to_scan,
  5249. globus_size_t * end_of_chunk_ext)
  5250. {
  5251. globus_size_t i;
  5252. globus_size_t j;
  5253. globus_bool_t semicolon = GLOBUS_FALSE;
  5254. /*
  5255. * chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
  5256. * chunk-ext-name = token
  5257. * chunk-ext-val = token | quoted-string
  5258. */
  5259. *end_of_chunk_ext = 0;
  5260. i = 0;
  5261. for(;;)
  5262. {
  5263. if(max_to_scan - i == 0)
  5264. {
  5265. return GLOBUS_TRUE;
  5266. }
  5267. else if (input[i] != CR)
  5268. {
  5269. /* Don't scan *LWS if the first character is a newline. Assume that no
  5270. * client will stick \r\n\t; as a chunk extension start.
  5271. */
  5272. if(globus_l_gass_transfer_http_scan_star_lws(
  5273. input + i,
  5274. max_to_scan - i,
  5275. &j))
  5276. {
  5277. return GLOBUS_TRUE; /* more to scan */
  5278. }
  5279. else if(input[i] != CR && j != 0)
  5280. {
  5281. i += j; /* scanned some leading LWS */
  5282. }
  5283. }
  5284. if(i + 1 >= max_to_scan)
  5285. {
  5286. return GLOBUS_TRUE;
  5287. }
  5288. /*
  5289. * Only consume LWS if there is a semicolon,
  5290. * otherwise, we may consume part of CRLF/message body
  5291. */
  5292. if(input[i] != ';' && semicolon)
  5293. {
  5294. *end_of_chunk_ext = i;
  5295. return GLOBUS_FALSE;
  5296. }
  5297. else if(input[i] != ';')
  5298. {
  5299. return GLOBUS_FALSE;
  5300. }
  5301. semicolon = GLOBUS_TRUE;
  5302. /* pass over ';' */
  5303. i++;
  5304. /* skip any LWS */
  5305. if(globus_l_gass_transfer_http_scan_star_lws(
  5306. input + i,
  5307. max_to_scan - i,
  5308. &j))
  5309. {
  5310. return GLOBUS_TRUE; /* more to scan */
  5311. }
  5312. else if(j != 0)
  5313. {
  5314. i += j; /* scanned some LWS */
  5315. }
  5316. /* scan for chunk-ext-name */
  5317. if(globus_l_gass_transfer_http_scan_token(
  5318. input + i,
  5319. max_to_scan - i,
  5320. &j))
  5321. {
  5322. return GLOBUS_TRUE;
  5323. }
  5324. else if(j == 0) /* illegal, ';' but no token */
  5325. {
  5326. *end_of_chunk_ext = 0;
  5327. return GLOBUS_FALSE;
  5328. }
  5329. else
  5330. {
  5331. i += j;
  5332. }
  5333. /* skip any LWS */
  5334. if(globus_l_gass_transfer_http_scan_star_lws(
  5335. input + i,
  5336. max_to_scan - i,
  5337. &j))
  5338. {
  5339. return GLOBUS_TRUE; /* more to scan */
  5340. }
  5341. else if(j != 0)
  5342. {
  5343. i += j; /* scanned some leading LWS */
  5344. }
  5345. /* check for '=' */
  5346. if(i + 1 >= max_to_scan)
  5347. {
  5348. return GLOBUS_TRUE;
  5349. }
  5350. if(input[i] == ';') /* chunk-ext without chunk-ext-value */
  5351. {
  5352. continue;
  5353. }
  5354. else if(input[i] != '=')
  5355. {
  5356. *end_of_chunk_ext = i;
  5357. return GLOBUS_FALSE;
  5358. }
  5359. /* pass over '=' */
  5360. i++;
  5361. /* skip any LWS */
  5362. if(globus_l_gass_transfer_http_scan_star_lws(
  5363. input+i,
  5364. max_to_scan-i,
  5365. &j))
  5366. {
  5367. return GLOBUS_TRUE; /* more to scan */
  5368. }
  5369. else if(j != 0)
  5370. {
  5371. i += j; /* scanned some LWS */
  5372. }
  5373. /* check for chunk-ext-value, either a token, or a quoted-string */
  5374. if(globus_l_gass_transfer_http_scan_token(
  5375. input + i,
  5376. max_to_scan - i,
  5377. &j))
  5378. {
  5379. return GLOBUS_TRUE; /* more to scan */
  5380. }
  5381. /* no token, try to scan quoted string */
  5382. else if(j == 0 &&
  5383. globus_l_gass_transfer_http_scan_quoted_string(
  5384. input + i,
  5385. max_to_scan - i,
  5386. &j))
  5387. {
  5388. return GLOBUS_TRUE; /* more to scan */
  5389. }
  5390. else
  5391. {
  5392. i += j;
  5393. }
  5394. }
  5395. }
  5396. /* globus_l_gass_transfer_http_scan_chunk_ext() */
  5397. static
  5398. globus_bool_t
  5399. globus_l_gass_transfer_http_scan_chunk_size(
  5400. globus_byte_t * input,
  5401. globus_size_t max_to_scan,
  5402. globus_size_t * end_of_chunk_size)
  5403. {
  5404. globus_size_t i;
  5405. /*
  5406. * hex-no-zero = <HEX excluding "0">
  5407. * chunk-size = hex-no-zero *HEX
  5408. */
  5409. *end_of_chunk_size = 0;
  5410. i = 0;
  5411. if(i >= max_to_scan)
  5412. {
  5413. return GLOBUS_TRUE;
  5414. }
  5415. if(input[i] == '0' &&
  5416. i + 1 < max_to_scan)
  5417. {
  5418. *end_of_chunk_size = 1;
  5419. return GLOBUS_FALSE;
  5420. }
  5421. for(; i < max_to_scan; i++)
  5422. {
  5423. if(input[i] == ' ' ||
  5424. input[i] == '\t')
  5425. {
  5426. continue;
  5427. }
  5428. if(!ishex(input[i]))
  5429. {
  5430. *end_of_chunk_size = i;
  5431. return GLOBUS_FALSE;
  5432. }
  5433. }
  5434. return GLOBUS_TRUE;
  5435. }
  5436. /* globus_l_gass_transfer_http_scan_chunk_size() */
  5437. /*
  5438. * Function: globus_l_gass_transfer_http_handle_chunk()
  5439. *
  5440. * Description: Parse any chunk header/footer information, and
  5441. * copy chunk data (with appropriate text-mode
  5442. * translations) into the user's buffers
  5443. *
  5444. * Parameters:
  5445. *
  5446. * Returns:
  5447. */
  5448. static
  5449. globus_bool_t
  5450. globus_l_gass_transfer_http_handle_chunk(
  5451. globus_gass_transfer_http_request_proto_t * proto)
  5452. {
  5453. globus_size_t i;
  5454. if ( proto->response_offset - proto->parsed_offset == 0 )
  5455. {
  5456. if (!proto->eof_read )
  5457. {
  5458. return GLOBUS_TRUE;
  5459. }
  5460. else
  5461. {
  5462. switch(proto->recv_state)
  5463. {
  5464. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH:
  5465. if (proto->length == proto->handled)
  5466. {
  5467. proto->recv_state =
  5468. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  5469. }
  5470. else
  5471. {
  5472. proto->recv_state =
  5473. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5474. }
  5475. break;
  5476. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF:
  5477. proto->recv_state =
  5478. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  5479. break;
  5480. default:
  5481. proto->failure_occurred = GLOBUS_TRUE;
  5482. proto->recv_state =
  5483. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5484. break;
  5485. }
  5486. return GLOBUS_FALSE;
  5487. }
  5488. }
  5489. while(proto->response_offset - proto->parsed_offset > 0)
  5490. {
  5491. switch(proto->recv_state)
  5492. {
  5493. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE:
  5494. if(globus_l_gass_transfer_http_scan_chunk_size(
  5495. proto->response_buffer + proto->parsed_offset,
  5496. proto->response_offset - proto->parsed_offset,
  5497. &i))
  5498. {
  5499. /* true == need more data */
  5500. return GLOBUS_TRUE;
  5501. }
  5502. else if(i == 0)
  5503. {
  5504. proto->recv_state =
  5505. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5506. proto->failure_occurred =
  5507. GLOBUS_TRUE;
  5508. return GLOBUS_FALSE;
  5509. }
  5510. proto->chunk_left = strtoul((char *) proto->response_buffer +
  5511. proto->parsed_offset,
  5512. GLOBUS_NULL,
  5513. 16);
  5514. proto->parsed_offset += i;
  5515. if(proto->chunk_left == 0)
  5516. {
  5517. /*
  5518. * last chunk can not be followed by chunk-ext elements,
  5519. * but may be followed by a set of footers
  5520. */
  5521. proto->recv_state =
  5522. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_FOOTER;
  5523. break;
  5524. }
  5525. else
  5526. {
  5527. proto->recv_state =
  5528. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_EXT;
  5529. }
  5530. /* FALLSTHROUGH */
  5531. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_EXT:
  5532. if(globus_l_gass_transfer_http_scan_chunk_ext(
  5533. proto->response_buffer + proto->parsed_offset,
  5534. proto->response_offset - proto->parsed_offset,
  5535. &i))
  5536. {
  5537. /* true == need more data */
  5538. return GLOBUS_TRUE;
  5539. }
  5540. else
  5541. {
  5542. proto->parsed_offset += i;
  5543. proto->recv_state =
  5544. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_CR;
  5545. /* FALLSTHROUGH */
  5546. }
  5547. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_CR:
  5548. if(proto->response_offset - proto->parsed_offset > 0)
  5549. {
  5550. if(proto->response_buffer[proto->parsed_offset] != CR)
  5551. {
  5552. proto->parse_error=GLOBUS_TRUE;
  5553. proto->failure_occurred = GLOBUS_TRUE;
  5554. proto->recv_state =
  5555. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5556. return GLOBUS_FALSE;
  5557. }
  5558. proto->recv_state =
  5559. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_LF;
  5560. proto->parsed_offset++;
  5561. }
  5562. else
  5563. {
  5564. return GLOBUS_TRUE;
  5565. }
  5566. /* FALLSTHROUGH */
  5567. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_LF:
  5568. if(proto->response_offset - proto->parsed_offset > 0)
  5569. {
  5570. if(proto->response_buffer[proto->parsed_offset] != LF)
  5571. {
  5572. proto->parse_error=GLOBUS_TRUE;
  5573. proto->failure_occurred=GLOBUS_TRUE;
  5574. return GLOBUS_FALSE;
  5575. }
  5576. proto->recv_state =
  5577. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY;
  5578. proto->parsed_offset++;
  5579. }
  5580. else
  5581. {
  5582. return GLOBUS_TRUE;
  5583. }
  5584. /* FALLSTHROUGH */
  5585. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY:
  5586. if(proto->chunk_left == 0)
  5587. {
  5588. proto->recv_state =
  5589. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_CR;
  5590. }
  5591. else
  5592. {
  5593. break;
  5594. }
  5595. /* FALLSTHROUGH */
  5596. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_CR:
  5597. if(proto->response_offset - proto->parsed_offset > 0)
  5598. {
  5599. if(proto->response_buffer[proto->parsed_offset] != CR)
  5600. {
  5601. proto->parse_error=GLOBUS_TRUE;
  5602. proto->failure_occurred=GLOBUS_TRUE;
  5603. proto->recv_state =
  5604. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5605. return GLOBUS_FALSE;
  5606. }
  5607. proto->recv_state =
  5608. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_LF;
  5609. proto->parsed_offset++;
  5610. }
  5611. else
  5612. {
  5613. return GLOBUS_TRUE;
  5614. }
  5615. /* FALLSTHROUGH */
  5616. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_LF:
  5617. if(proto->response_offset - proto->parsed_offset > 0)
  5618. {
  5619. if(proto->response_buffer[proto->parsed_offset] != LF)
  5620. {
  5621. proto->parse_error=GLOBUS_TRUE;
  5622. proto->failure_occurred=GLOBUS_TRUE;
  5623. proto->recv_state =
  5624. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5625. return GLOBUS_FALSE;
  5626. }
  5627. proto->recv_state =
  5628. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
  5629. proto->parsed_offset++;
  5630. break;
  5631. }
  5632. else
  5633. {
  5634. return GLOBUS_TRUE;
  5635. }
  5636. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_FOOTER:
  5637. if(globus_l_gass_transfer_http_parse_headers(proto))
  5638. {
  5639. /* need more data */
  5640. return GLOBUS_TRUE;
  5641. }
  5642. else if(proto->parse_error)
  5643. {
  5644. proto->failure_occurred=GLOBUS_TRUE;
  5645. proto->recv_state =
  5646. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5647. return GLOBUS_FALSE;
  5648. }
  5649. else
  5650. {
  5651. proto->recv_state =
  5652. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  5653. return GLOBUS_FALSE;
  5654. }
  5655. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF:
  5656. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH:
  5657. break;
  5658. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR:
  5659. case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF:
  5660. return GLOBUS_FALSE;
  5661. }
  5662. if(proto->recv_state ==
  5663. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH ||
  5664. proto->recv_state ==
  5665. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF ||
  5666. proto->recv_state ==
  5667. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY)
  5668. {
  5669. if(proto->user_buflen > proto->user_offset &&
  5670. proto->response_offset > proto->parsed_offset)
  5671. {
  5672. /* some room is in the user's buffer for new data */
  5673. if(proto->text_mode)
  5674. {
  5675. globus_l_gass_transfer_unbuffer_text(proto);
  5676. }
  5677. else
  5678. {
  5679. globus_l_gass_transfer_unbuffer_binary(proto);
  5680. }
  5681. /* check to see if we've failed/completed because of this */
  5682. if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
  5683. proto->length == proto->handled)
  5684. {
  5685. proto->recv_state =
  5686. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  5687. }
  5688. else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
  5689. proto->eof_read &&
  5690. proto->response_offset - proto->parsed_offset == 0)
  5691. {
  5692. proto->recv_state =
  5693. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
  5694. }
  5695. else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF &&
  5696. proto->eof_read &&
  5697. proto->response_offset - proto->parsed_offset == 0)
  5698. {
  5699. proto->recv_state =
  5700. GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
  5701. }
  5702. }
  5703. else
  5704. {
  5705. return GLOBUS_FALSE;
  5706. }
  5707. }
  5708. }
  5709. return GLOBUS_FALSE;
  5710. }
  5711. /* globus_l_gass_transfer_http_handle_chunk() */
  5712. static
  5713. void
  5714. globus_l_gass_transfer_http_extract_referral(
  5715. globus_gass_transfer_http_request_proto_t * proto,
  5716. char *** referral,
  5717. globus_size_t * referral_count)
  5718. {
  5719. char * location;
  5720. char * p;
  5721. location = globus_i_gass_transfer_keyvalue_lookup(
  5722. &proto->headers,
  5723. "location");
  5724. if(location == GLOBUS_NULL)
  5725. {
  5726. *referral = GLOBUS_NULL;
  5727. *referral_count = 0;
  5728. }
  5729. else
  5730. {
  5731. p = location;
  5732. for(p=location; *p != '\0'; p++)
  5733. {
  5734. if(!isspace(*p))
  5735. {
  5736. break;
  5737. }
  5738. }
  5739. *referral = (char **) globus_malloc(sizeof(char *));
  5740. (*referral)[0] = globus_libc_strdup(p);
  5741. *referral_count = 1;
  5742. }
  5743. return;
  5744. }
  5745. /* globus_l_gass_transfer_http_extract_referral() */
  5746. static
  5747. void
  5748. globus_l_gass_transfer_http_accept_failed_kickout(
  5749. void * arg)
  5750. {
  5751. globus_l_gass_transfer_failed_kickout_closure_t *
  5752. closure;
  5753. closure = (globus_l_gass_transfer_failed_kickout_closure_t *) arg;
  5754. globus_gass_transfer_proto_new_listener_request(
  5755. closure->l_proto->listener,
  5756. closure->request,
  5757. GLOBUS_NULL);
  5758. globus_libc_free(closure);
  5759. }
  5760. #if !defined(GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST)
  5761. static
  5762. void
  5763. globus_l_gass_transfer_http_callback_denied(
  5764. void * arg)
  5765. {
  5766. globus_gass_transfer_request_t request;
  5767. request = (globus_gass_transfer_request_t) arg;
  5768. debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
  5769. globus_gass_transfer_proto_request_denied(
  5770. request,
  5771. GLOBUS_L_DEFAULT_FAILURE_CODE,
  5772. globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON));
  5773. }
  5774. #endif /* !GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST */
  5775. #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */