response_headers_handler.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /** **************************************************************************
  2. * response_headers_handler.c
  3. *
  4. * Copyright 2008 Bryan Ischo <[email protected]>
  5. *
  6. * This file is part of libs3.
  7. *
  8. * libs3 is free software: you can redistribute it and/or modify it under the
  9. * terms of the GNU Lesser General Public License as published by the Free
  10. * Software Foundation, version 3 or above of the License. You can also
  11. * redistribute and/or modify it under the terms of the GNU General Public
  12. * License, version 2 or above of the License.
  13. *
  14. * In addition, as a special exception, the copyright holders give
  15. * permission to link the code of this library and its programs with the
  16. * OpenSSL library, and distribute linked combinations including the two.
  17. *
  18. * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
  19. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  20. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  21. * details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public License
  24. * version 3 along with libs3, in a file named COPYING. If not, see
  25. * <https://www.gnu.org/licenses/>.
  26. *
  27. * You should also have received a copy of the GNU General Public License
  28. * version 2 along with libs3, in a file named COPYING-GPLv2. If not, see
  29. * <https://www.gnu.org/licenses/>.
  30. *
  31. ************************************************************************** **/
  32. #include <ctype.h>
  33. #include <string.h>
  34. #ifndef WINSCP
  35. #include <strings.h>
  36. #endif
  37. #include "response_headers_handler.h"
  38. #ifdef WINSCP
  39. #include "ne_dates.h"
  40. #endif
  41. void response_headers_handler_initialize(ResponseHeadersHandler *handler)
  42. {
  43. handler->responseProperties.requestId = 0;
  44. handler->responseProperties.requestId2 = 0;
  45. handler->responseProperties.contentType = 0;
  46. handler->responseProperties.contentLength = 0;
  47. handler->responseProperties.server = 0;
  48. handler->responseProperties.eTag = 0;
  49. handler->responseProperties.lastModified = -1;
  50. handler->responseProperties.metaDataCount = 0;
  51. handler->responseProperties.metaData = 0;
  52. handler->responseProperties.usesServerSideEncryption = 0;
  53. handler->done = 0;
  54. string_multibuffer_initialize(handler->responsePropertyStrings);
  55. string_multibuffer_initialize(handler->responseMetaDataStrings);
  56. }
  57. void response_headers_handler_add(ResponseHeadersHandler *handler,
  58. const char * header_name, const char * header_value) // WINSCP (neon API)
  59. {
  60. S3ResponseProperties *responseProperties = &(handler->responseProperties);
  61. // Curl might call back the header function after the body has been
  62. // received, for 'chunked encoded' contents. We don't handle this as of
  63. // yet, and it's not clear that it would ever be useful.
  64. if (handler->done) {
  65. return;
  66. }
  67. // If we've already filled up the response headers, ignore this data.
  68. // This sucks, but it shouldn't happen - S3 should not be sending back
  69. // really long headers.
  70. if (handler->responsePropertyStringsSize ==
  71. (sizeof(handler->responsePropertyStrings) - 1)) {
  72. return;
  73. }
  74. int valuelen = strlen(header_value), fit;
  75. const char * c = header_value;
  76. int namelen = strlen(header_name);
  77. const char * header = header_name;
  78. #define strncasecmp strnicmp // WINSCP
  79. if (!strncasecmp(header, "x-amz-request-id", namelen)) {
  80. responseProperties->requestId =
  81. string_multibuffer_current(handler->responsePropertyStrings);
  82. string_multibuffer_add(handler->responsePropertyStrings, c,
  83. valuelen, fit);
  84. }
  85. else if (!strncasecmp(header, "x-amz-id-2", namelen)) {
  86. responseProperties->requestId2 =
  87. string_multibuffer_current(handler->responsePropertyStrings);
  88. string_multibuffer_add(handler->responsePropertyStrings, c,
  89. valuelen, fit);
  90. }
  91. else if (!strncasecmp(header, "Content-Type", namelen)) {
  92. responseProperties->contentType =
  93. string_multibuffer_current(handler->responsePropertyStrings);
  94. string_multibuffer_add(handler->responsePropertyStrings, c,
  95. valuelen, fit);
  96. }
  97. else if (!strncasecmp(header, "Content-Length", namelen)) {
  98. handler->responseProperties.contentLength = 0;
  99. while (*c) {
  100. handler->responseProperties.contentLength *= 10;
  101. handler->responseProperties.contentLength += (*c++ - '0');
  102. }
  103. }
  104. else if (!strncasecmp(header, "Server", namelen)) {
  105. responseProperties->server =
  106. string_multibuffer_current(handler->responsePropertyStrings);
  107. string_multibuffer_add(handler->responsePropertyStrings, c,
  108. valuelen, fit);
  109. }
  110. else if ((!strncasecmp(header, "ETag", namelen))
  111. || (!strncasecmp(header, "Etag", namelen))) { // some servers reply with Etag header
  112. responseProperties->eTag =
  113. string_multibuffer_current(handler->responsePropertyStrings);
  114. string_multibuffer_add(handler->responsePropertyStrings, c,
  115. valuelen, fit);
  116. }
  117. else if (!strncasecmp(header, S3_METADATA_HEADER_NAME_PREFIX,
  118. sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)) {
  119. // Make sure there is room for another x-amz-meta header
  120. if (handler->responseProperties.metaDataCount ==
  121. sizeof(handler->responseMetaData)) {
  122. return;
  123. }
  124. // Copy the name in
  125. const char *metaName = &(header[sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1]);
  126. int metaNameLen =
  127. (namelen - (sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1));
  128. char *copiedName =
  129. string_multibuffer_current(handler->responseMetaDataStrings);
  130. string_multibuffer_add(handler->responseMetaDataStrings, metaName,
  131. metaNameLen, fit);
  132. if (!fit) {
  133. return;
  134. }
  135. // Copy the value in
  136. char *copiedValue =
  137. string_multibuffer_current(handler->responseMetaDataStrings);
  138. string_multibuffer_add(handler->responseMetaDataStrings,
  139. c, valuelen, fit);
  140. if (!fit) {
  141. return;
  142. }
  143. if (!handler->responseProperties.metaDataCount) {
  144. handler->responseProperties.metaData =
  145. handler->responseMetaData;
  146. }
  147. S3NameValue *metaHeader =
  148. &(handler->responseMetaData
  149. [handler->responseProperties.metaDataCount++]);
  150. metaHeader->name = copiedName;
  151. metaHeader->value = copiedValue;
  152. }
  153. else if (!strncasecmp(header, "x-amz-server-side-encryption", namelen)) {
  154. if (!strncmp(c, "AES256", sizeof("AES256") - 1)) {
  155. responseProperties->usesServerSideEncryption = 1;
  156. }
  157. // Ignore other values - only AES256 is expected, anything else is
  158. // assumed to be "None" or some other value indicating no server-side
  159. // encryption
  160. }
  161. }
  162. void response_headers_handler_done(ResponseHeadersHandler *handler, ne_request *NeonRequest) // WINSCP (neon API)
  163. {
  164. const char * value = ne_get_response_header(NeonRequest, "Last-Modified");
  165. if (value != NULL) {
  166. handler->responseProperties.lastModified = ne_httpdate_parse(value);
  167. }
  168. handler->done = 1;
  169. }