HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NET_WebResponse.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: NET_WebResponse.h
7  *
8  * COMMENTS:
9  *
10  */
11 
12 #ifndef __NET_WEBRESPONSE_H__
13 #define __NET_WEBRESPONSE_H__
14 
15 #include "NET_API.h"
16 
17 #include "NET_HTTPDefines.h"
18 #include "NET_Time.h"
19 #include "NET_WebTypes.h"
20 
21 #include <UT/UT_Array.h>
22 #include <UT/UT_ArrayStringMap.h>
23 #include <UT/UT_Assert.h>
24 #include <UT/UT_Debug.h>
25 #include <UT/UT_ErrorCode.h>
26 #include <UT/UT_Optional.h>
27 #include <UT/UT_SharedPtr.h>
28 #include <UT/UT_StringArray.h>
29 #include <UT/UT_StringHolder.h>
30 #include <UT/UT_Url.h>
31 
32 #include <SYS/SYS_Types.h>
33 
34 #include <time.h>
35 
36 class NET_NetworkCookie;
37 class UT_WorkBuffer;
38 
39 // NOTE: Not a full list of http status codes
41 {
42  // Curl uses zero to indicate no status code received
44  // Info Codes
47  // Success Codes
48  NET_HTTPOk = 200,
55  // Redirect Codes
63  // Client Error Codes
74  NET_HTTPGone = 410,
89  // Server Error Codes
98 };
99 
100 /// Holds all common information between a client response and an object holding
101 /// the servers response to a client.
103 {
104 public:
110  NET_HTTPStatusCode code,
111  const HeaderMap &headers,
112  const UT_StringHolder &data);
113  NET_BaseWebResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
114 
115  explicit operator bool() const { return isSuccess(); }
116 
117  bool isSuccess() const { return myStatus == NET_HTTPOk; }
118 
119  bool isRequestNotFound() const { return myStatus == NET_HTTPNotFound; }
120  bool isBadRequest() const { return myStatus == NET_HTTPBadRequest; }
121  bool hasTimedout() const { return myStatus == NET_HTTPRequestTimeout; }
122 
123  UT_StringHolder headersAsString() const;
124 
125  // Does this response object have a specific option specified.
126  bool hasHeader(const UT_StringRef &header) const;
127 
128  void setDefault(const UT_StringHolder& name, const UT_StringHolder& value);
129 
130  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
131  {
132  auto it = myHeaders.find(header);
133  if (it == myHeaders.end())
135  return it->second;
136  }
137  UT_Optional<UT_StringHolder> getHeaderContentType();
139  {
140  auto it = myHeaders.find(HTTP_CONTENT_TYPE);
141  if (it == myHeaders.end())
143  return it->second;
144  }
145  UT_Optional<exint> getHeaderContentLength();
146 
147  bool hasContentType(const UT_StringRef &mime) const;
148 
149  NET_Time modTime() const;
150 
151  // Get the stock message based on the status code
152  static void stockMsgFromCode(NET_HTTPStatusCode code, UT_WorkBuffer &msg);
153 
154  bool hasJSONBody() const;
155  bool hasTextBody() const;
156  static bool isJSONBody(const HeaderMap &headers);
157 
158  // The status of the response
160  // The headers of the response
163  // The body of the response
165 };
166 
167 namespace NET
168 {
169 enum class CurlError
170 {
171  INTERNAL_ERROR = -1,
172  OK = 0,
174  FAILED_INIT,
176  NOT_BUILT_IN,
190  PARTIAL_FILE,
192  QUOTE_ERROR,
194  WRITE_ERROR,
196  READ_ERROR,
201  RANGE_ERROR,
216  GOT_NOTHING,
219  SEND_ERROR,
220  RECV_ERROR,
222  SSL_CIPHER,
230  LOGIN_DENIED,
233  TFTP_ILLEGAL,
237  CONV_FAILED,
238  CONV_REQD,
241  SSH_ERROR,
243  AGAIN_ERROR,
250  CHUNK_FAILED,
254  HTTP2_STREAM,
256  AUTH_ERROR,
257  HTTP3_ERROR,
259  PROXY_ERROR,
261  TFTP_PERM,
262  LAST
263 };
264 
266 
267 inline UT_ErrorCode
269 {
270  return UT_ErrorCode{static_cast<int>(e), GetCurlErrorCategory()};
271 }
272 } // namespace NET
273 
274 namespace std
275 {
276  template <> struct is_error_code_enum<NET::CurlError> : true_type
277  {
278  };
279 }
280 
281 /// Contains extra information that might be useful. Note this only contains
282 /// extra details for the NET::CurlError
284 
285 /// Response object used by a client from a response by a server.
287 {
288 public:
289  struct NET_API Error
290  {
291  UT_StringHolder buildErrorMessage(const UT_Url& effective_url) const;
292  static UT_ErrorCode translateErrorToCode(int err);
293 
295  // Explenation of the error
297  bool myMaxRetriesHit = false;
298  // Total number of attempts made when myMaxRetriesHit is set, so error
299  // messages can report how many times we tried before giving up.
300  int myAttempts = 0;
301 
302  private:
303  friend class NET_HTTPResponse;
304  };
305 
310  NET_HTTPStatusCode code,
311  const HeaderMap &headers,
312  const UT_StringHolder &data);
313  NET_HTTPResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
314 
315  void parseCookies(UT_Array<NET_NetworkCookie> &cookies) const;
316  bool errorReceivedNothing() const
317  {
318  return myError.myErrorCode
320  }
321  void clear();
323  {
325  }
326 
328 
331 
334 
336 };
337 
338 /// Response object used for responding to request in the server.
340 {
341 public:
343 
346  {
348  }
351  {
352  _init(code);
353  }
356  {
357  _init(code);
358  setBody(data);
359  }
361  NET_HTTPStatusCode code,
362  const HeaderMap &headers,
363  const UT_StringHolder &data)
365  {
366  _init(code);
367  setHeaders(headers);
368  setBody(data);
369  }
372  {
373  _init(code);
374  setHeaders(headers);
375  }
376 
377  NET_WebResponse(const NET_WebResponse &resp) = default;
378  NET_WebResponse &operator=(const NET_WebResponse &resp) = default;
379  NET_WebResponse(NET_WebResponse &&resp) = default;
380  NET_WebResponse &operator=(NET_WebResponse &&resp) = default;
381 
382  // Convience operators to forward a client response as a server response
385  {
386  _init(resp.myStatus);
387  setHeaders(resp.myHeaders);
388  setBody(resp.myData);
389  }
391  {
392  _init();
393  setHeaders(resp.myHeaders);
394  setBody(resp.myData);
395  return *this;
396  }
397 
398  void clear();
399 
400  bool isFile() const { return myFile.isstring(); }
401 
402  bool isChunked() const
403  {
404  return myChunked;
405  }
406  bool hasHeader(const UT_StringRef& header) const
407  {
408  return NET_BaseWebResponse::hasHeader(header);
409  }
410  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
411  {
413  }
414 
416  {
417  return NET_BaseWebResponse::setDefault(name, value);
418  }
419 
421  {
422  myStatus = code;
423 
424  if (myStatus == NET_HTTPNoContent ||
425  myStatus == NET_HTTPNotModified)
426  {
427  myChunked = true;
428  }
429  }
430  NET_HTTPStatusCode status() const { return myStatus; }
431 
432  // Set a header entry. An empty header value means to remove the entry.
433  void setHeader(const UT_StringRef& name, const UT_StringRef& value);
434  void setHeaders(const HeaderMap& headers)
435  {
436  for (auto&& header : headers)
437  {
438  setHeader(header.first, header.second);
439  }
440  }
441  // Used whenever a header can have a list of values attached to it
442  // (i.e. Vary)
443  void patchHeader(const UT_StringHolder& name, const UT_StringHolder& value);
444 
445  // Set the response as an in memory response
446  void setBody(const UT_StringHolder& body, const UT_StringRef& content_type = "")
447  {
448  clearFile();
449 
450  myData = body;
451  if (!content_type.isEmpty())
452  myContentType = content_type;
453  else if (myContentType.isEmpty())
454  myContentType = "text/plain";
455  myContentLength = myData.length();
456  }
457  // Set the next chunk to send. This only updates the body and if there is
458  // more data to be processed. The chunked header MUST be set prior to
459  // calling this function.
460  void setBodyChunk(const UT_StringHolder& body, bool has_more = false)
461  {
462  UT_ASSERT(myChunked);
463 
464  myHasMoreData = has_more;
465  myData = body;
466  }
467  // Helper method to set a text body
468  void setText(const UT_StringHolder& body)
469  {
470  setBody(body, "text/plain");
471  }
472  void setJSON(const UT_StringHolder& body)
473  {
474  setBody(body, "application/json");
475  }
476  // Set the response as a file response.
477  void setFile(const UT_StringHolder& file, bool delete_file);
478  void clearBody()
479  {
480  myData.clear();
481  }
482  void clearFile()
483  {
484  myFile.clear();
485  myDeleteFile = false;
486  myHeaders.erase(HTTP_LAST_MODIFIED);
487  }
488  // Set the ranges for our response.
489  void setRanges(const NET_RequestRangeList& ranges)
490  {
491  myRanges = ranges;
492  // Create a boundary if we have multiple ranges
493  //
494  // NB: we dont set/change the content type as we will just set the
495  // content type when sending so that the body can send the proper
496  // content type when its time to send this information.
497  if (ranges.entries() > 1)
498  myBoundary.format("-----{}", time(nullptr) ^ (uint64)(this));
499  else
500  myBoundary.clear();
501 
502  setHeader(HTTP_ACCEPT_RANGES, "bytes");
503  }
504 
505  void clearRanges()
506  {
507  myRanges.clear();
508  myBoundary.clear();
509  myHeaders.erase(HTTP_ACCEPT_RANGES);
510  }
511 
512  bool shouldClose() const
513  {
514  if (!myKeepAlive)
515  return true;
516 
517  if (myUpgrade)
518  return false;
519 
520  if (myStatus > 499)
521  return true;
522 
523  return false;
524  }
525  const UT_StringHolder& data() const
526  {
527  return myData;
528  }
529  exint contentLength() const { return myContentLength; }
530  const UT_StringHolder& contentType() const { return myContentType; }
531  const HeaderMap& headers() const { return myHeaders; }
532  bool isUpgrade() const { return myUpgrade; }
533  void setErrors(const UT_StringHolder& errors)
534  {
535  myErrors = errors;
536  }
537  const NET_RequestRangeList& ranges() const { return myRanges; }
538  const UT_StringHolder& boundary() const { return myBoundary; }
539  bool isTempFile() const { return myDeleteFile; }
540  const UT_StringHolder& file() const { return myFile; }
541  // True if there is more data that needs to be sent. This only has meaning
542  // if the response is chunked.
543  bool hasMoreData() const { return myHasMoreData; }
544  bool keepAlive() const { return myKeepAlive; }
545  void setKeepAlive(bool keep_alive) { myKeepAlive = keep_alive; }
546 
547  void addCookie(const NET_NetworkCookie& cookie);
548  void deleteCookie(const UT_StringRef& name);
549  bool hasCookie(const UT_StringRef& name) const;
550  bool getCookie(const UT_StringRef& name, NET_NetworkCookie& cookie) const;
551 private:
553  {
554  myChunked = false;
555 
556  setStatus(code);
557 
558  myHeaders.clear();
559  myCookies.clear();
560 
561  myContentType.clear();
562  myBoundary.clear();
563  myContentLength = 0;
564 
565  myFile.clear();
566  myDeleteFile = false;
567 
568  myRanges.clear();
569 
570  myData.clear();
571 
572  myUpgrade = false;
573 
574  myHasMoreData = false;
575  myKeepAlive = true;
576 
577  myErrors.clear();
578  }
579 
580 private:
581  friend class NET_HttpIO;
582 
583  NET_RequestRangeList myRanges;
584 
585  UT_StringHolder myContentType;
586  UT_StringHolder myBoundary;
587  exint myContentLength;
588 
589  UT_StringHolder myFile;
590  unsigned myDeleteFile : 1;
591  unsigned myUpgrade : 1;
592  unsigned myChunked : 1;
593  unsigned myHasMoreData : 1;
594  unsigned myKeepAlive : 1;
595  // Error that you might want hidden
596  UT_StringHolder myErrors;
597 };
598 
600 
601 #endif // __NET_WEBRESPONSE_H__
602 
NET_HTTPStatusCode status() const
const UT_StringHolder & contentTypeOrEmpty() const
void setDefault(const UT_StringHolder &name, const UT_StringHolder &value)
UT_StringHolder myEffectiveMethod
Response object used for responding to request in the server.
void setErrors(const UT_StringHolder &errors)
GT_API const UT_StringHolder time
GLsizei const GLfloat * value
Definition: glcorearb.h:824
NET_API const UT_ErrorCategory & GetCurlErrorCategory()
int64 exint
Definition: SYS_Types.h:125
void setKeepAlive(bool keep_alive)
UT_StringHolder myData
NET_WebResponse(NET_HTTPStatusCode code, const UT_StringHolder &data)
bool isFile() const
bool isTempFile() const
std::error_category UT_ErrorCategory
Definition: UT_ErrorCode.h:22
unsigned long long uint64
Definition: SYS_Types.h:117
NET_HTTPStatusCode
OutGridT const XformOp bool bool
const UT_StringHolder & getHeaderOrEmpty(const UT_StringRef &header) const
std::optional< T > UT_Optional
Definition: UT_Optional.h:26
void setRanges(const NET_RequestRangeList &ranges)
UT_ErrorCode make_error_code(NET::CurlError e)
UT_StringArray myCookies
double fpreal64
Definition: SYS_Types.h:201
#define NET_API
Definition: NET_API.h:9
void setText(const UT_StringHolder &body)
bool hasHeader(const UT_StringRef &header) const
UT_StringHolder buildErrorMessage(const UT_Url &effective_url) const
Response object used by a client from a response by a server.
exint length() const
void setStatus(NET_HTTPStatusCode code)
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
bool isRequestNotFound() const
static const UT_StringHolder theEmptyString
void setJSON(const UT_StringHolder &body)
bool shouldClose() const
void setDefault(const UT_StringHolder &name, const UT_StringHolder &value)
Definition: UT_Url.h:26
const HeaderMap & headers() const
UT_SharedPtr< NET_WebResponse > NET_WebResponseSPtr
UT_ArrayStringMap< UT_StringHolder > HeaderMap
const UT_StringHolder & boundary() const
GLuint const GLchar * name
Definition: glcorearb.h:786
bool isUpgrade() const
UT_StringHolder myErrorMsg
void parseCookies(UT_Array< NET_NetworkCookie > &cookies) const
bool isSuccess() const
bool keepAlive() const
NET_WebResponse(NET_HTTPStatusCode code, const HeaderMap &headers, const UT_StringHolder &data)
#define HTTP_ACCEPT_RANGES
NET_HTTPStatusCode myStatus
std::error_code UT_ErrorCode
Definition: UT_ErrorCode.h:20
bool hasMoreData() const
NET_WebResponse(NET_HTTPStatusCode code)
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:669
NET_API UT_StringHolder NETextraDetails(const UT_ErrorCode &ec)
#define HTTP_LAST_MODIFIED
NET_WebResponse & operator=(const NET_HTTPResponse &resp)
void setBody(const UT_StringHolder &body, const UT_StringRef &content_type="")
LeafData & operator=(const LeafData &)=delete
const NET_RequestRangeList & ranges() const
const UT_StringHolder & data() const
void setHeaders(const HeaderMap &headers)
const UT_StringHolder & getHeaderOrEmpty(const UT_StringRef &header) const
exint contentLength() const
NET_WebResponse(NET_HTTPStatusCode code, const HeaderMap &headers)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
void setBodyChunk(const UT_StringHolder &body, bool has_more=false)
UT_StringHolder myFileName
bool errorReceivedNothing() const
bool isChunked() const
const UT_StringHolder & file() const
bool hasHeader(const UT_StringRef &header) const
void clear()
Resets list to an empty list.
Definition: UT_Array.h:753
const UT_StringHolder & contentType() const
bool hasTimedout() const
Definition: format.h:1821
#define HTTP_CONTENT_TYPE
bool isBadRequest() const
UT_StringHolder errorMessage() const
NET_WebResponse(const NET_HTTPResponse &resp)