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 <SYS/SYS_Types.h>
31 
32 #include <time.h>
33 
34 class NET_NetworkCookie;
35 class UT_WorkBuffer;
36 
37 // NOTE: Not a full list of http status codes
39 {
40  // Curl uses zero to indicate no status code received
42  // Info Codes
45  // Success Codes
46  NET_HTTPOk = 200,
53  // Redirect Codes
61  // Client Error Codes
72  NET_HTTPGone = 410,
87  // Server Error Codes
95 };
96 
97 /// Holds all common information between a client response and an object holding
98 /// the servers response to a client.
100 {
101 public:
107  NET_HTTPStatusCode code,
108  const HeaderMap &headers,
109  const UT_StringHolder &data);
110  NET_BaseWebResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
111 
112  explicit operator bool() const { return isSuccess(); }
113 
114  bool isSuccess() const { return myStatus == NET_HTTPOk; }
115 
116  bool isRequestNotFound() const { return myStatus == NET_HTTPNotFound; }
117  bool isBadRequest() const { return myStatus == NET_HTTPBadRequest; }
118  bool hasTimedout() const { return myStatus == NET_HTTPRequestTimeout; }
119 
120  UT_StringHolder headersAsString() const;
121 
122  // Does this response object have a specific option specified.
123  bool hasHeader(const UT_StringRef &header) const;
124 
125  void setDefault(const UT_StringHolder& name, const UT_StringHolder& value);
126 
127  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
128  {
129  auto it = myHeaders.find(header);
130  if (it == myHeaders.end())
132  return it->second;
133  }
134  UT_Optional<UT_StringHolder> getHeaderContentType();
136  {
137  auto it = myHeaders.find(HTTP_CONTENT_TYPE);
138  if (it == myHeaders.end())
140  return it->second;
141  }
142  UT_Optional<exint> getHeaderContentLength();
143 
144  bool hasContentType(const UT_StringRef &mime) const;
145 
146  NET_Time modTime() const;
147 
148  // Get the stock message based on the status code
149  static void stockMsgFromCode(NET_HTTPStatusCode code, UT_WorkBuffer &msg);
150 
151  bool hasJSONBody() const;
152  static bool isJSONBody(const HeaderMap &headers);
153 
154  // The status of the response
156  // The headers of the response
159  // The body of the response
161 };
162 
163 namespace NET
164 {
165 enum class CurlError
166 {
167  INTERNAL_ERROR = -1,
168  OK = 0,
170  FAILED_INIT,
172  NOT_BUILT_IN,
186  PARTIAL_FILE,
188  QUOTE_ERROR,
190  WRITE_ERROR,
192  READ_ERROR,
197  RANGE_ERROR,
211  GOT_NOTHING,
214  SEND_ERROR,
215  RECV_ERROR,
217  SSL_CIPHER,
225  LOGIN_DENIED,
228  TFTP_ILLEGAL,
232  CONV_FAILED,
233  CONV_REQD,
236  SSH_ERROR,
238  AGAIN_ERROR,
245  CHUNK_FAILED,
249  HTTP2_STREAM,
251  AUTH_ERROR,
252  HTTP3_ERROR,
254  OBSOLETE
255 };
256 
258 
259 inline UT_ErrorCode
261 {
262  return UT_ErrorCode{static_cast<int>(e), GetCurlErrorCategory()};
263 }
264 } // namespace NET
265 
266 namespace std
267 {
268  template <> struct is_error_code_enum<NET::CurlError> : true_type
269  {
270  };
271 }
272 
273 /// Contains extra information that might be useful. Note this only contains
274 /// extra details for the NET::CurlError
276 
277 /// Response object used by a client from a response by a server.
279 {
280 public:
281  struct NET_API Error
282  {
283  UT_StringHolder buildErrorMessage() const;
284  static UT_ErrorCode translateErrorToCode(int err);
285 
287  // Explenation of the error
289  };
290 
295  NET_HTTPStatusCode code,
296  const HeaderMap &headers,
297  const UT_StringHolder &data);
298  NET_HTTPResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
299 
300  void parseCookies(UT_Array<NET_NetworkCookie> &cookies) const;
301  bool errorReceivedNothing() const
302  {
303  return myError.myErrorCode
305  }
306  void clear();
307 
309 
310  fpreal64 myConnectTime = 0.0f;
311  fpreal64 myTotalTime = 0.0f;
312 };
313 
314 /// Response object used for responding to request in the server.
316 {
317 public:
319 
322  {
324  }
327  {
328  _init(code);
329  }
332  {
333  _init(code);
334  setBody(data);
335  }
337  NET_HTTPStatusCode code,
338  const HeaderMap &headers,
339  const UT_StringHolder &data)
341  {
342  _init(code);
343  setHeaders(headers);
344  setBody(data);
345  }
348  {
349  _init(code);
350  setHeaders(headers);
351  }
352 
353  NET_WebResponse(const NET_WebResponse &resp) = default;
354  NET_WebResponse &operator=(const NET_WebResponse &resp) = default;
355  NET_WebResponse(NET_WebResponse &&resp) = default;
356  NET_WebResponse &operator=(NET_WebResponse &&resp) = default;
357 
358  // Convience operators to forward a client response as a server response
361  {
362  _init(resp.myStatus);
363  setHeaders(resp.myHeaders);
364  setBody(resp.myData);
365  }
367  {
368  _init();
369  setHeaders(resp.myHeaders);
370  setBody(resp.myData);
371  return *this;
372  }
373 
374  void clear();
375 
376  bool isFile() const { return myFile.isstring(); }
377 
378  bool isChunked() const
379  {
380  return myChunked;
381  }
382  bool hasHeader(const UT_StringRef& header) const
383  {
384  return NET_BaseWebResponse::hasHeader(header);
385  }
386 
388  {
389  return NET_BaseWebResponse::setDefault(name, value);
390  }
391 
393  {
394  myStatus = code;
395 
396  if (myStatus == NET_HTTPNoContent ||
397  myStatus == NET_HTTPNotModified)
398  {
399  myChunked = true;
400  }
401  }
402  NET_HTTPStatusCode status() const { return myStatus; }
403 
404  // Set a header entry. An empty header value means to remove the entry.
405  void setHeader(const UT_StringRef& name, const UT_StringRef& value);
406  void setHeaders(const HeaderMap& headers)
407  {
408  for (auto&& header : headers)
409  {
410  setHeader(header.first, header.second);
411  }
412  }
413  // Used whenever a header can have a list of values attached to it
414  // (i.e. Vary)
415  void patchHeader(const UT_StringHolder& name, const UT_StringHolder& value);
416 
417  // Set the response as an in memory response
418  void setBody(const UT_StringHolder& body, const UT_StringRef& content_type = "")
419  {
420  clearFile();
421 
422  myData = body;
423  if (!content_type.isEmpty())
424  myContentType = content_type;
425  else if (myContentType.isEmpty())
426  myContentType = "text/plain";
427  myContentLength = myData.length();
428  }
429  // Set the next chunk to send. This only updates the body and if there is
430  // more data to be processed. The chunked header MUST be set prior to
431  // calling this function.
432  void setBodyChunk(const UT_StringHolder& body, bool has_more = false)
433  {
434  UT_ASSERT(myChunked);
435 
436  myHasMoreData = has_more;
437  myData = body;
438  }
439  // Helper method to set a text body
440  void setText(const UT_StringHolder& body)
441  {
442  setBody(body, "text/plain");
443  }
444  void setJSON(const UT_StringHolder& body)
445  {
446  setBody(body, "application/json");
447  }
448  // Set the response as a file response.
449  void setFile(const UT_StringHolder& file, bool delete_file);
450  void clearBody()
451  {
452  myData.clear();
453  }
454  void clearFile()
455  {
456  myFile.clear();
457  myDeleteFile = false;
458  myHeaders.erase(HTTP_LAST_MODIFIED);
459  }
460  // Set the ranges for our response.
461  void setRanges(const NET_RequestRangeList& ranges)
462  {
463  myRanges = ranges;
464  // Create a boundary if we have multiple ranges
465  //
466  // NB: we dont set/change the content type as we will just set the
467  // content type when sending so that the body can send the proper
468  // content type when its time to send this information.
469  if (ranges.entries() > 1)
470  myBoundary.format("-----{}", time(nullptr) ^ (uint64)(this));
471  else
472  myBoundary.clear();
473 
474  setHeader(HTTP_ACCEPT_RANGES, "bytes");
475  }
476 
477  void clearRanges()
478  {
479  myRanges.clear();
480  myBoundary.clear();
481  myHeaders.erase(HTTP_ACCEPT_RANGES);
482  }
483 
484  bool shouldClose() const
485  {
486  if (!myKeepAlive)
487  return true;
488 
489  if (myUpgrade)
490  return false;
491 
492  if (myStatus > 499)
493  return true;
494 
495  return false;
496  }
497  const UT_StringHolder& data() const
498  {
499  return myData;
500  }
501  exint contentLength() const { return myContentLength; }
502  const UT_StringHolder& contentType() const { return myContentType; }
503  const HeaderMap& headers() const { return myHeaders; }
504  bool isUpgrade() const { return myUpgrade; }
505  void setErrors(const UT_StringHolder& errors)
506  {
507  myErrors = errors;
508  }
509  const NET_RequestRangeList& ranges() const { return myRanges; }
510  const UT_StringHolder& boundary() const { return myBoundary; }
511  bool isTempFile() const { return myDeleteFile; }
512  const UT_StringHolder& file() const { return myFile; }
513  // True if there is more data that needs to be sent. This only has meaning
514  // if the response is chunked.
515  bool hasMoreData() const { return myHasMoreData; }
516  bool keepAlive() const { return myKeepAlive; }
517  void setKeepAlive(bool keep_alive) { myKeepAlive = keep_alive; }
518 private:
520  {
521  myChunked = false;
522 
523  setStatus(code);
524 
525  myHeaders.clear();
526  myCookies.clear();
527 
528  myContentType.clear();
529  myBoundary.clear();
530  myContentLength = 0;
531 
532  myFile.clear();
533  myDeleteFile = false;
534 
535  myRanges.clear();
536 
537  myData.clear();
538 
539  myUpgrade = false;
540 
541  myHasMoreData = false;
542  myKeepAlive = true;
543 
544  myErrors.clear();
545  }
546 
547 private:
548  friend class NET_HttpIO;
549 
550  NET_RequestRangeList myRanges;
551 
552  UT_StringHolder myContentType;
553  UT_StringHolder myBoundary;
554  exint myContentLength;
555 
556  UT_StringHolder myFile;
557  unsigned myDeleteFile : 1;
558  unsigned myUpgrade : 1;
559  unsigned myChunked : 1;
560  unsigned myHasMoreData : 1;
561  unsigned myKeepAlive : 1;
562  // Error that you might want hidden
563  UT_StringHolder myErrors;
564 };
565 
567 
568 #endif // __NET_WEBRESPONSE_H__
569 
NET_HTTPStatusCode status() const
const UT_StringHolder & contentTypeOrEmpty() const
void setDefault(const UT_StringHolder &name, const UT_StringHolder &value)
Response object used for responding to request in the server.
void setErrors(const UT_StringHolder &errors)
GT_API const UT_StringHolder time
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
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
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)
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
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:648
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="")
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:156
void setBodyChunk(const UT_StringHolder &body, bool has_more=false)
Definition: core.h:1131
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:716
const UT_StringHolder & contentType() const
bool hasTimedout() const
Definition: format.h:895
#define HTTP_CONTENT_TYPE
bool isBadRequest() const
NET_WebResponse(const NET_HTTPResponse &resp)