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  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
387  {
389  }
390 
392  {
393  return NET_BaseWebResponse::setDefault(name, value);
394  }
395 
397  {
398  myStatus = code;
399 
400  if (myStatus == NET_HTTPNoContent ||
401  myStatus == NET_HTTPNotModified)
402  {
403  myChunked = true;
404  }
405  }
406  NET_HTTPStatusCode status() const { return myStatus; }
407 
408  // Set a header entry. An empty header value means to remove the entry.
409  void setHeader(const UT_StringRef& name, const UT_StringRef& value);
410  void setHeaders(const HeaderMap& headers)
411  {
412  for (auto&& header : headers)
413  {
414  setHeader(header.first, header.second);
415  }
416  }
417  // Used whenever a header can have a list of values attached to it
418  // (i.e. Vary)
419  void patchHeader(const UT_StringHolder& name, const UT_StringHolder& value);
420 
421  // Set the response as an in memory response
422  void setBody(const UT_StringHolder& body, const UT_StringRef& content_type = "")
423  {
424  clearFile();
425 
426  myData = body;
427  if (!content_type.isEmpty())
428  myContentType = content_type;
429  else if (myContentType.isEmpty())
430  myContentType = "text/plain";
431  myContentLength = myData.length();
432  }
433  // Set the next chunk to send. This only updates the body and if there is
434  // more data to be processed. The chunked header MUST be set prior to
435  // calling this function.
436  void setBodyChunk(const UT_StringHolder& body, bool has_more = false)
437  {
438  UT_ASSERT(myChunked);
439 
440  myHasMoreData = has_more;
441  myData = body;
442  }
443  // Helper method to set a text body
444  void setText(const UT_StringHolder& body)
445  {
446  setBody(body, "text/plain");
447  }
448  void setJSON(const UT_StringHolder& body)
449  {
450  setBody(body, "application/json");
451  }
452  // Set the response as a file response.
453  void setFile(const UT_StringHolder& file, bool delete_file);
454  void clearBody()
455  {
456  myData.clear();
457  }
458  void clearFile()
459  {
460  myFile.clear();
461  myDeleteFile = false;
462  myHeaders.erase(HTTP_LAST_MODIFIED);
463  }
464  // Set the ranges for our response.
465  void setRanges(const NET_RequestRangeList& ranges)
466  {
467  myRanges = ranges;
468  // Create a boundary if we have multiple ranges
469  //
470  // NB: we dont set/change the content type as we will just set the
471  // content type when sending so that the body can send the proper
472  // content type when its time to send this information.
473  if (ranges.entries() > 1)
474  myBoundary.format("-----{}", time(nullptr) ^ (uint64)(this));
475  else
476  myBoundary.clear();
477 
478  setHeader(HTTP_ACCEPT_RANGES, "bytes");
479  }
480 
481  void clearRanges()
482  {
483  myRanges.clear();
484  myBoundary.clear();
485  myHeaders.erase(HTTP_ACCEPT_RANGES);
486  }
487 
488  bool shouldClose() const
489  {
490  if (!myKeepAlive)
491  return true;
492 
493  if (myUpgrade)
494  return false;
495 
496  if (myStatus > 499)
497  return true;
498 
499  return false;
500  }
501  const UT_StringHolder& data() const
502  {
503  return myData;
504  }
505  exint contentLength() const { return myContentLength; }
506  const UT_StringHolder& contentType() const { return myContentType; }
507  const HeaderMap& headers() const { return myHeaders; }
508  bool isUpgrade() const { return myUpgrade; }
509  void setErrors(const UT_StringHolder& errors)
510  {
511  myErrors = errors;
512  }
513  const NET_RequestRangeList& ranges() const { return myRanges; }
514  const UT_StringHolder& boundary() const { return myBoundary; }
515  bool isTempFile() const { return myDeleteFile; }
516  const UT_StringHolder& file() const { return myFile; }
517  // True if there is more data that needs to be sent. This only has meaning
518  // if the response is chunked.
519  bool hasMoreData() const { return myHasMoreData; }
520  bool keepAlive() const { return myKeepAlive; }
521  void setKeepAlive(bool keep_alive) { myKeepAlive = keep_alive; }
522 
523  void addCookie(const NET_NetworkCookie& cookie);
524  void deleteCookie(const UT_StringRef& name);
525  bool hasCookie(const UT_StringRef& name) const;
526  bool getCookie(const UT_StringRef& name, NET_NetworkCookie& cookie) const;
527 private:
529  {
530  myChunked = false;
531 
532  setStatus(code);
533 
534  myHeaders.clear();
535  myCookies.clear();
536 
537  myContentType.clear();
538  myBoundary.clear();
539  myContentLength = 0;
540 
541  myFile.clear();
542  myDeleteFile = false;
543 
544  myRanges.clear();
545 
546  myData.clear();
547 
548  myUpgrade = false;
549 
550  myHasMoreData = false;
551  myKeepAlive = true;
552 
553  myErrors.clear();
554  }
555 
556 private:
557  friend class NET_HttpIO;
558 
559  NET_RequestRangeList myRanges;
560 
561  UT_StringHolder myContentType;
562  UT_StringHolder myBoundary;
563  exint myContentLength;
564 
565  UT_StringHolder myFile;
566  unsigned myDeleteFile : 1;
567  unsigned myUpgrade : 1;
568  unsigned myChunked : 1;
569  unsigned myHasMoreData : 1;
570  unsigned myKeepAlive : 1;
571  // Error that you might want hidden
572  UT_StringHolder myErrors;
573 };
574 
576 
577 #endif // __NET_WEBRESPONSE_H__
578 
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
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
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="")
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: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:729
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)