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
96 };
97 
98 /// Holds all common information between a client response and an object holding
99 /// the servers response to a client.
101 {
102 public:
108  NET_HTTPStatusCode code,
109  const HeaderMap &headers,
110  const UT_StringHolder &data);
111  NET_BaseWebResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
112 
113  explicit operator bool() const { return isSuccess(); }
114 
115  bool isSuccess() const { return myStatus == NET_HTTPOk; }
116 
117  bool isRequestNotFound() const { return myStatus == NET_HTTPNotFound; }
118  bool isBadRequest() const { return myStatus == NET_HTTPBadRequest; }
119  bool hasTimedout() const { return myStatus == NET_HTTPRequestTimeout; }
120 
121  UT_StringHolder headersAsString() const;
122 
123  // Does this response object have a specific option specified.
124  bool hasHeader(const UT_StringRef &header) const;
125 
126  void setDefault(const UT_StringHolder& name, const UT_StringHolder& value);
127 
128  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
129  {
130  auto it = myHeaders.find(header);
131  if (it == myHeaders.end())
133  return it->second;
134  }
135  UT_Optional<UT_StringHolder> getHeaderContentType();
137  {
138  auto it = myHeaders.find(HTTP_CONTENT_TYPE);
139  if (it == myHeaders.end())
141  return it->second;
142  }
143  UT_Optional<exint> getHeaderContentLength();
144 
145  bool hasContentType(const UT_StringRef &mime) const;
146 
147  NET_Time modTime() const;
148 
149  // Get the stock message based on the status code
150  static void stockMsgFromCode(NET_HTTPStatusCode code, UT_WorkBuffer &msg);
151 
152  bool hasJSONBody() const;
153  static bool isJSONBody(const HeaderMap &headers);
154 
155  // The status of the response
157  // The headers of the response
160  // The body of the response
162 };
163 
164 namespace NET
165 {
166 enum class CurlError
167 {
168  INTERNAL_ERROR = -1,
169  OK = 0,
171  FAILED_INIT,
173  NOT_BUILT_IN,
187  PARTIAL_FILE,
189  QUOTE_ERROR,
191  WRITE_ERROR,
193  READ_ERROR,
198  RANGE_ERROR,
213  GOT_NOTHING,
216  SEND_ERROR,
217  RECV_ERROR,
219  SSL_CIPHER,
227  LOGIN_DENIED,
230  TFTP_ILLEGAL,
234  CONV_FAILED,
235  CONV_REQD,
238  SSH_ERROR,
240  AGAIN_ERROR,
247  CHUNK_FAILED,
251  HTTP2_STREAM,
253  AUTH_ERROR,
254  HTTP3_ERROR,
256  PROXY_ERROR,
258  TFTP_PERM,
259  LAST
260 };
261 
263 
264 inline UT_ErrorCode
266 {
267  return UT_ErrorCode{static_cast<int>(e), GetCurlErrorCategory()};
268 }
269 } // namespace NET
270 
271 namespace std
272 {
273  template <> struct is_error_code_enum<NET::CurlError> : true_type
274  {
275  };
276 }
277 
278 /// Contains extra information that might be useful. Note this only contains
279 /// extra details for the NET::CurlError
281 
282 /// Response object used by a client from a response by a server.
284 {
285 public:
286  struct NET_API Error
287  {
288  UT_StringHolder buildErrorMessage() const;
289  static UT_ErrorCode translateErrorToCode(int err);
290 
292  // Explenation of the error
294  };
295 
300  NET_HTTPStatusCode code,
301  const HeaderMap &headers,
302  const UT_StringHolder &data);
303  NET_HTTPResponse(NET_HTTPStatusCode code, const HeaderMap &headers);
304 
305  void parseCookies(UT_Array<NET_NetworkCookie> &cookies) const;
306  bool errorReceivedNothing() const
307  {
308  return myError.myErrorCode
310  }
311  void clear();
312 
314 
315  fpreal64 myConnectTime = 0.0f;
316  fpreal64 myTotalTime = 0.0f;
317 
319 };
320 
321 /// Response object used for responding to request in the server.
323 {
324 public:
326 
329  {
331  }
334  {
335  _init(code);
336  }
339  {
340  _init(code);
341  setBody(data);
342  }
344  NET_HTTPStatusCode code,
345  const HeaderMap &headers,
346  const UT_StringHolder &data)
348  {
349  _init(code);
350  setHeaders(headers);
351  setBody(data);
352  }
355  {
356  _init(code);
357  setHeaders(headers);
358  }
359 
360  NET_WebResponse(const NET_WebResponse &resp) = default;
361  NET_WebResponse &operator=(const NET_WebResponse &resp) = default;
362  NET_WebResponse(NET_WebResponse &&resp) = default;
363  NET_WebResponse &operator=(NET_WebResponse &&resp) = default;
364 
365  // Convience operators to forward a client response as a server response
368  {
369  _init(resp.myStatus);
370  setHeaders(resp.myHeaders);
371  setBody(resp.myData);
372  }
374  {
375  _init();
376  setHeaders(resp.myHeaders);
377  setBody(resp.myData);
378  return *this;
379  }
380 
381  void clear();
382 
383  bool isFile() const { return myFile.isstring(); }
384 
385  bool isChunked() const
386  {
387  return myChunked;
388  }
389  bool hasHeader(const UT_StringRef& header) const
390  {
391  return NET_BaseWebResponse::hasHeader(header);
392  }
393  const UT_StringHolder& getHeaderOrEmpty(const UT_StringRef& header) const
394  {
396  }
397 
399  {
400  return NET_BaseWebResponse::setDefault(name, value);
401  }
402 
404  {
405  myStatus = code;
406 
407  if (myStatus == NET_HTTPNoContent ||
408  myStatus == NET_HTTPNotModified)
409  {
410  myChunked = true;
411  }
412  }
413  NET_HTTPStatusCode status() const { return myStatus; }
414 
415  // Set a header entry. An empty header value means to remove the entry.
416  void setHeader(const UT_StringRef& name, const UT_StringRef& value);
417  void setHeaders(const HeaderMap& headers)
418  {
419  for (auto&& header : headers)
420  {
421  setHeader(header.first, header.second);
422  }
423  }
424  // Used whenever a header can have a list of values attached to it
425  // (i.e. Vary)
426  void patchHeader(const UT_StringHolder& name, const UT_StringHolder& value);
427 
428  // Set the response as an in memory response
429  void setBody(const UT_StringHolder& body, const UT_StringRef& content_type = "")
430  {
431  clearFile();
432 
433  myData = body;
434  if (!content_type.isEmpty())
435  myContentType = content_type;
436  else if (myContentType.isEmpty())
437  myContentType = "text/plain";
438  myContentLength = myData.length();
439  }
440  // Set the next chunk to send. This only updates the body and if there is
441  // more data to be processed. The chunked header MUST be set prior to
442  // calling this function.
443  void setBodyChunk(const UT_StringHolder& body, bool has_more = false)
444  {
445  UT_ASSERT(myChunked);
446 
447  myHasMoreData = has_more;
448  myData = body;
449  }
450  // Helper method to set a text body
451  void setText(const UT_StringHolder& body)
452  {
453  setBody(body, "text/plain");
454  }
455  void setJSON(const UT_StringHolder& body)
456  {
457  setBody(body, "application/json");
458  }
459  // Set the response as a file response.
460  void setFile(const UT_StringHolder& file, bool delete_file);
461  void clearBody()
462  {
463  myData.clear();
464  }
465  void clearFile()
466  {
467  myFile.clear();
468  myDeleteFile = false;
469  myHeaders.erase(HTTP_LAST_MODIFIED);
470  }
471  // Set the ranges for our response.
472  void setRanges(const NET_RequestRangeList& ranges)
473  {
474  myRanges = ranges;
475  // Create a boundary if we have multiple ranges
476  //
477  // NB: we dont set/change the content type as we will just set the
478  // content type when sending so that the body can send the proper
479  // content type when its time to send this information.
480  if (ranges.entries() > 1)
481  myBoundary.format("-----{}", time(nullptr) ^ (uint64)(this));
482  else
483  myBoundary.clear();
484 
485  setHeader(HTTP_ACCEPT_RANGES, "bytes");
486  }
487 
488  void clearRanges()
489  {
490  myRanges.clear();
491  myBoundary.clear();
492  myHeaders.erase(HTTP_ACCEPT_RANGES);
493  }
494 
495  bool shouldClose() const
496  {
497  if (!myKeepAlive)
498  return true;
499 
500  if (myUpgrade)
501  return false;
502 
503  if (myStatus > 499)
504  return true;
505 
506  return false;
507  }
508  const UT_StringHolder& data() const
509  {
510  return myData;
511  }
512  exint contentLength() const { return myContentLength; }
513  const UT_StringHolder& contentType() const { return myContentType; }
514  const HeaderMap& headers() const { return myHeaders; }
515  bool isUpgrade() const { return myUpgrade; }
516  void setErrors(const UT_StringHolder& errors)
517  {
518  myErrors = errors;
519  }
520  const NET_RequestRangeList& ranges() const { return myRanges; }
521  const UT_StringHolder& boundary() const { return myBoundary; }
522  bool isTempFile() const { return myDeleteFile; }
523  const UT_StringHolder& file() const { return myFile; }
524  // True if there is more data that needs to be sent. This only has meaning
525  // if the response is chunked.
526  bool hasMoreData() const { return myHasMoreData; }
527  bool keepAlive() const { return myKeepAlive; }
528  void setKeepAlive(bool keep_alive) { myKeepAlive = keep_alive; }
529 
530  void addCookie(const NET_NetworkCookie& cookie);
531  void deleteCookie(const UT_StringRef& name);
532  bool hasCookie(const UT_StringRef& name) const;
533  bool getCookie(const UT_StringRef& name, NET_NetworkCookie& cookie) const;
534 private:
536  {
537  myChunked = false;
538 
539  setStatus(code);
540 
541  myHeaders.clear();
542  myCookies.clear();
543 
544  myContentType.clear();
545  myBoundary.clear();
546  myContentLength = 0;
547 
548  myFile.clear();
549  myDeleteFile = false;
550 
551  myRanges.clear();
552 
553  myData.clear();
554 
555  myUpgrade = false;
556 
557  myHasMoreData = false;
558  myKeepAlive = true;
559 
560  myErrors.clear();
561  }
562 
563 private:
564  friend class NET_HttpIO;
565 
566  NET_RequestRangeList myRanges;
567 
568  UT_StringHolder myContentType;
569  UT_StringHolder myBoundary;
570  exint myContentLength;
571 
572  UT_StringHolder myFile;
573  unsigned myDeleteFile : 1;
574  unsigned myUpgrade : 1;
575  unsigned myChunked : 1;
576  unsigned myHasMoreData : 1;
577  unsigned myKeepAlive : 1;
578  // Error that you might want hidden
579  UT_StringHolder myErrors;
580 };
581 
583 
584 #endif // __NET_WEBRESPONSE_H__
585 
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
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
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:655
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)
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:736
const UT_StringHolder & contentType() const
bool hasTimedout() const
Definition: format.h:1821
#define HTTP_CONTENT_TYPE
bool isBadRequest() const
NET_WebResponse(const NET_HTTPResponse &resp)