XRootD
XrdHttpUtils.cc File Reference

Utility functions for XrdHTTP. More...

#include "XrdHttpUtils.hh"
#include <cstring>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "sys/param.h"
#include <pthread.h>
#include <memory>
#include <vector>
#include <algorithm>
#include "XrdSec/XrdSecEntity.hh"
#include "XrdOuc/XrdOucString.hh"
+ Include dependency graph for XrdHttpUtils.cc:

Go to the source code of this file.

Functions

void base64DecodeHex (const std::string &base64, std::string &hexOutput)
 
void base64ToBytes (const std::string &base64digest, std::vector< uint8_t > &outputBytes)
 
void bytesToHex (const std::vector< uint8_t > &bytes, std::string &output)
 
void calcHashes (char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
 
static int char_to_int (int ch)
 
int compareHash (const char *h1, const char *h2)
 
char * escapeXML (const char *str)
 
bool Fromhexdigest (const std::string &hex, std::vector< uint8_t > &outputBytes)
 
std::string httpStatusToString (int status)
 
std::string itos (long i)
 
int mapErrNoToHttp (int errNo)
 
int mapXrdErrToHttp (XErrorCode xrdError)
 
char * mystrchrnul (const char *s, int c)
 
char * quote (const char *str)
 
void Tobase64 (const std::vector< uint8_t > &input, std::string &base64Output)
 
void Tobase64 (const unsigned char *input, int length, char *out)
 
char * unquote (char *str)
 

Detailed Description

Utility functions for XrdHTTP.

Author
Fabrizio Furano
Date
April 2013

Definition in file XrdHttpUtils.cc.

Function Documentation

◆ base64DecodeHex()

void base64DecodeHex ( const std::string &  base64,
std::string &  hexOutput 
)

Definition at line 155 of file XrdHttpUtils.cc.

155  {
156  std::vector<uint8_t> bytes;
157  base64ToBytes(base64,bytes);
158  bytesToHex(bytes, hexOutput);
159 }
void base64ToBytes(const std::string &base64digest, std::vector< uint8_t > &outputBytes)
void bytesToHex(const std::vector< uint8_t > &bytes, std::string &output)

References base64ToBytes(), and bytesToHex().

Referenced by XrdHttpHeaderUtils::parseReprDigest().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ base64ToBytes()

void base64ToBytes ( const std::string &  base64digest,
std::vector< uint8_t > &  outputBytes 
)

Definition at line 118 of file XrdHttpUtils.cc.

118  {
119  outputBytes.clear();
120 
121  if (base64digest.empty()) {
122  return;
123  }
124 
125  BIO *b64 = BIO_new(BIO_f_base64());
126  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); // match your encoder
127 
128  BIO *bmem = BIO_new_mem_buf(base64digest.data(), static_cast<int>(base64digest.size()));
129  bmem = BIO_push(b64, bmem);
130 
131  // Estimate maximum size (base64 expands data by ~33%)
132  std::vector<uint8_t> buffer(base64digest.size());
133 
134  int decodedLen = BIO_read(bmem, buffer.data(), static_cast<int>(buffer.size()));
135  if (decodedLen > 0) {
136  buffer.resize(decodedLen);
137  outputBytes.swap(buffer);
138  } else {
139  outputBytes.clear(); // decoding failed
140  }
141 
142  BIO_free_all(bmem);
143 }

Referenced by base64DecodeHex().

+ Here is the caller graph for this function:

◆ bytesToHex()

void bytesToHex ( const std::vector< uint8_t > &  bytes,
std::string &  output 
)

Definition at line 145 of file XrdHttpUtils.cc.

145  {
146  static const char* lut = "0123456789abcdef";
147  output.clear();
148  output.reserve(bytes.size() * 2);
149  for (uint8_t b : bytes) {
150  output.push_back(lut[b >> 4]);
151  output.push_back(lut[b & 0x0F]);
152  }
153 }

Referenced by base64DecodeHex().

+ Here is the caller graph for this function:

◆ calcHashes()

void calcHashes ( char *  hash,
const char *  fn,
kXR_int16  request,
XrdSecEntity secent,
time_t  tim,
const char *  key 
)

Definition at line 231 of file XrdHttpUtils.cc.

242  {
243 
244 
245 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
246  EVP_MAC *mac;
247  EVP_MAC_CTX *ctx;
248  size_t len;
249 #else
250  HMAC_CTX *ctx;
251  unsigned int len;
252 #endif
253  unsigned char mdbuf[EVP_MAX_MD_SIZE];
254  char buf[64];
255  struct tm tms;
256 
257 
258  if (!hash) {
259  return;
260  }
261  hash[0] = '\0';
262 
263  if (!key) {
264  return;
265  }
266 
267  if (!fn || !secent) {
268  return;
269  }
270 
271 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
272 
273  mac = EVP_MAC_fetch(0, "sha256", 0);
274  ctx = EVP_MAC_CTX_new(mac);
275 
276  if (!ctx) {
277  return;
278  }
279 
280 
281  EVP_MAC_init(ctx, (const unsigned char *) key, strlen(key), 0);
282 
283 
284  if (fn)
285  EVP_MAC_update(ctx, (const unsigned char *) fn,
286  strlen(fn) + 1);
287 
288  EVP_MAC_update(ctx, (const unsigned char *) &request,
289  sizeof (request));
290 
291  if (secent->name)
292  EVP_MAC_update(ctx, (const unsigned char *) secent->name,
293  strlen(secent->name) + 1);
294 
295  if (secent->vorg)
296  EVP_MAC_update(ctx, (const unsigned char *) secent->vorg,
297  strlen(secent->vorg) + 1);
298 
299  if (secent->host)
300  EVP_MAC_update(ctx, (const unsigned char *) secent->host,
301  strlen(secent->host) + 1);
302 
303  if (secent->moninfo)
304  EVP_MAC_update(ctx, (const unsigned char *) secent->moninfo,
305  strlen(secent->moninfo) + 1);
306 
307  localtime_r(&tim, &tms);
308  strftime(buf, sizeof (buf), "%s", &tms);
309  EVP_MAC_update(ctx, (const unsigned char *) buf,
310  strlen(buf) + 1);
311 
312  EVP_MAC_final(ctx, mdbuf, &len, EVP_MAX_MD_SIZE);
313 
314  EVP_MAC_CTX_free(ctx);
315  EVP_MAC_free(mac);
316 
317 #else
318 
319  ctx = HMAC_CTX_new();
320 
321  if (!ctx) {
322  return;
323  }
324 
325 
326 
327  HMAC_Init_ex(ctx, (const void *) key, strlen(key), EVP_sha256(), 0);
328 
329 
330  if (fn)
331  HMAC_Update(ctx, (const unsigned char *) fn,
332  strlen(fn) + 1);
333 
334  HMAC_Update(ctx, (const unsigned char *) &request,
335  sizeof (request));
336 
337  if (secent->name)
338  HMAC_Update(ctx, (const unsigned char *) secent->name,
339  strlen(secent->name) + 1);
340 
341  if (secent->vorg)
342  HMAC_Update(ctx, (const unsigned char *) secent->vorg,
343  strlen(secent->vorg) + 1);
344 
345  if (secent->host)
346  HMAC_Update(ctx, (const unsigned char *) secent->host,
347  strlen(secent->host) + 1);
348 
349  if (secent->moninfo)
350  HMAC_Update(ctx, (const unsigned char *) secent->moninfo,
351  strlen(secent->moninfo) + 1);
352 
353  localtime_r(&tim, &tms);
354  strftime(buf, sizeof (buf), "%s", &tms);
355  HMAC_Update(ctx, (const unsigned char *) buf,
356  strlen(buf) + 1);
357 
358  HMAC_Final(ctx, mdbuf, &len);
359 
360  HMAC_CTX_free(ctx);
361 
362 #endif
363 
364  Tobase64(mdbuf, len / 2, hash);
365 }
void Tobase64(const unsigned char *input, int length, char *out)
Definition: XrdHttpUtils.cc:60
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70

References XrdSecEntity::host, XrdSecEntity::moninfo, XrdSecEntity::name, Tobase64(), and XrdSecEntity::vorg.

Referenced by XrdHttpProtocol::Process(), and XrdHttpReq::Redir().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ char_to_int()

static int char_to_int ( int  ch)
static

Definition at line 163 of file XrdHttpUtils.cc.

164 {
165  unsigned char c = static_cast<unsigned char>(ch);
166  if (std::isdigit(c)) {
167  return c - '0';
168  } else {
169  c = ::tolower(c);
170  if (c >= 'a' && c <= 'f') {
171  return c - 'a' + 10;
172  }
173  return -1;
174  }
175 }

Referenced by Fromhexdigest().

+ Here is the caller graph for this function:

◆ compareHash()

int compareHash ( const char *  h1,
const char *  h2 
)

Definition at line 367 of file XrdHttpUtils.cc.

369  {
370 
371  if (h1 == h2) return 0;
372 
373  if (!h1 || !h2)
374  return 1;
375 
376  return strcmp(h1, h2);
377 
378 }

Referenced by XrdHttpProtocol::Process().

+ Here is the caller graph for this function:

◆ escapeXML()

char* escapeXML ( const char *  str)

Definition at line 473 of file XrdHttpUtils.cc.

473  {
474  int l = strlen(str);
475  char *r = (char *) malloc(l*6 + 1);
476  r[0] = '\0';
477  int i, j = 0;
478 
479  for (i = 0; i < l; i++) {
480  char c = str[i];
481 
482  switch (c) {
483  case '"':
484  strcpy(r + j, "&quot;");
485  j += 6;
486  break;
487  case '&':
488  strcpy(r + j, "&amp;");
489  j += 5;
490  break;
491  case '<':
492  strcpy(r + j, "&lt;");
493  j += 4;
494  break;
495  case '>':
496  strcpy(r + j, "&gt;");
497  j += 4;
498  break;
499  case '\'':
500  strcpy(r + j, "&apos;");
501  j += 6;
502  break;
503 
504  default:
505  r[j++] = c;
506  }
507  }
508 
509  r[j] = '\0';
510 
511  return r;
512 }

Referenced by XrdHttpReq::Error().

+ Here is the caller graph for this function:

◆ Fromhexdigest()

bool Fromhexdigest ( const std::string &  hex,
std::vector< uint8_t > &  outputBytes 
)

Definition at line 177 of file XrdHttpUtils.cc.

177  {
178  if(hex.size() % 2 != 0) {
179  return false;
180  }
181 
182  outputBytes.reserve(hex.size() / 2);
183 
184  for(size_t i = 0; i < hex.size(); i += 2) {
185  int upper = char_to_int(hex[i]);
186  int lower = char_to_int(hex[i + 1]);
187  if (upper < 0 || lower < 0) return false;
188  outputBytes.push_back(static_cast<uint8_t>((upper << 4) + lower));
189  }
190  return true;
191 }
static int char_to_int(int ch)
@ hex
Definition: XrdSysTrace.hh:42

References char_to_int(), and Xrd::hex.

+ Here is the call graph for this function:

◆ httpStatusToString()

std::string httpStatusToString ( int  status)

Definition at line 594 of file XrdHttpUtils.cc.

594  {
595  switch (status) {
596  // 1xx Informational
597  case 100: return "Continue";
598  case 101: return "Switching Protocols";
599  case 102: return "Processing";
600  case 103: return "Early Hints";
601 
602  // 2xx Success
603  case 200: return "OK";
604  case 201: return "Created";
605  case 202: return "Accepted";
606  case 203: return "Non-Authoritative Information";
607  case 204: return "No Content";
608  case 205: return "Reset Content";
609  case 206: return "Partial Content";
610  case 207: return "Multi-Status";
611  case 208: return "Already Reported";
612  case 226: return "IM Used";
613 
614  // 3xx Redirection
615  case 300: return "Multiple Choices";
616  case 301: return "Moved Permanently";
617  case 302: return "Found";
618  case 303: return "See Other";
619  case 304: return "Not Modified";
620  case 305: return "Use Proxy";
621  case 307: return "Temporary Redirect";
622  case 308: return "Permanent Redirect";
623 
624  // 4xx Client Errors
625  case 400: return "Bad Request";
626  case 401: return "Unauthorized";
627  case 402: return "Payment Required";
628  case 403: return "Forbidden";
629  case 404: return "Not Found";
630  case 405: return "Method Not Allowed";
631  case 406: return "Not Acceptable";
632  case 407: return "Proxy Authentication Required";
633  case 408: return "Request Timeout";
634  case 409: return "Conflict";
635  case 410: return "Gone";
636  case 411: return "Length Required";
637  case 412: return "Precondition Failed";
638  case 413: return "Payload Too Large";
639  case 414: return "URI Too Long";
640  case 415: return "Unsupported Media Type";
641  case 416: return "Range Not Satisfiable";
642  case 417: return "Expectation Failed";
643  case 418: return "I'm a teapot";
644  case 421: return "Misdirected Request";
645  case 422: return "Unprocessable Entity";
646  case 423: return "Locked";
647  case 424: return "Failed Dependency";
648  case 425: return "Too Early";
649  case 426: return "Upgrade Required";
650  case 428: return "Precondition Required";
651  case 429: return "Too Many Requests";
652  case 431: return "Request Header Fields Too Large";
653  case 451: return "Unavailable For Legal Reasons";
654 
655  // 5xx Server Errors
656  case 500: return "Internal Server Error";
657  case 501: return "Not Implemented";
658  case 502: return "Bad Gateway";
659  case 503: return "Service Unavailable";
660  case 504: return "Gateway Timeout";
661  case 505: return "HTTP Version Not Supported";
662  case 506: return "Variant Also Negotiates";
663  case 507: return "Insufficient Storage";
664  case 508: return "Loop Detected";
665  case 510: return "Not Extended";
666  case 511: return "Network Authentication Required";
667 
668  default:
669  switch (status) {
670  case 100 ... 199: return "Informational";
671  case 200 ... 299: return "Success";
672  case 300 ... 399: return "Redirection";
673  case 400 ... 499: return "Client Error";
674  case 500 ... 599: return "Server Error";
675  default: return "Unknown";
676  }
677  }
678 }

◆ itos()

std::string itos ( long  i)

Definition at line 195 of file XrdHttpUtils.cc.

195  {
196  char buf[128];
197  sprintf(buf, "%ld", i);
198 
199  return buf;
200 }

◆ mapErrNoToHttp()

int mapErrNoToHttp ( int  errNo)

Definition at line 521 of file XrdHttpUtils.cc.

521  {
522 
523  switch (errNo) {
524 
525  case EACCES:
526  case EROFS:
527  case EPERM:
528  return HTTP_FORBIDDEN;
529 
530  case EAUTH:
531  return HTTP_UNAUTHORIZED;
532 
533  case ENOENT:
534  return HTTP_NOT_FOUND;
535 
536  case EEXIST:
537  case EISDIR:
538  case ENOTDIR:
539  case ENOTEMPTY:
540  return HTTP_CONFLICT;
541 
542  case EXDEV:
544 
545  case ENAMETOOLONG:
546  return HTTP_URI_TOO_LONG;
547 
548  case ELOOP:
549  return HTTP_LOOP_DETECTED;
550 
551  case ENOSPC:
552  case EDQUOT:
554 
555  case EFBIG:
556  return HTTP_PAYLOAD_TOO_LARGE;
557 
558  case EINVAL:
559  case EBADF:
560  case EFAULT:
561  case ENXIO:
562  case ESPIPE:
563  case EOVERFLOW:
564  return HTTP_BAD_REQUEST;
565 
566  case ENOTSUP: // EOPNOTSUPP
567  return HTTP_NOT_IMPLEMENTED;
568 
569  case EBUSY:
570  case EAGAIN:
571  case EINTR:
572  case ENOMEM:
573  case EMFILE:
574  case ENFILE:
575  case ETXTBSY:
577 
578  case ETIMEDOUT:
579  return HTTP_GATEWAY_TIMEOUT;
580 
581  case ECONNREFUSED:
582  case ECONNRESET:
583  case ENETDOWN:
584  case ENETUNREACH:
585  case EHOSTUNREACH:
586  case EPIPE:
587  return HTTP_BAD_GATEWAY;
588 
589  default:
591  }
592 }
#define EAUTH
Definition: XProtocol.hh:1393
@ HTTP_INSUFFICIENT_STORAGE
@ HTTP_BAD_REQUEST
Definition: XrdHttpUtils.hh:81
@ HTTP_LOOP_DETECTED
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_URI_TOO_LONG
Definition: XrdHttpUtils.hh:95
@ HTTP_UNAUTHORIZED
Definition: XrdHttpUtils.hh:82
@ HTTP_NOT_FOUND
Definition: XrdHttpUtils.hh:85
@ HTTP_FORBIDDEN
Definition: XrdHttpUtils.hh:84
@ HTTP_BAD_GATEWAY
@ HTTP_GATEWAY_TIMEOUT
@ HTTP_INTERNAL_SERVER_ERROR
@ HTTP_PAYLOAD_TOO_LARGE
Definition: XrdHttpUtils.hh:94
@ HTTP_NOT_IMPLEMENTED
@ HTTP_UNPROCESSABLE_ENTITY
@ HTTP_CONFLICT
Definition: XrdHttpUtils.hh:90

References EAUTH, HTTP_BAD_GATEWAY, HTTP_BAD_REQUEST, HTTP_CONFLICT, HTTP_FORBIDDEN, HTTP_GATEWAY_TIMEOUT, HTTP_INSUFFICIENT_STORAGE, HTTP_INTERNAL_SERVER_ERROR, HTTP_LOOP_DETECTED, HTTP_NOT_FOUND, HTTP_NOT_IMPLEMENTED, HTTP_PAYLOAD_TOO_LARGE, HTTP_SERVICE_UNAVAILABLE, HTTP_UNAUTHORIZED, HTTP_UNPROCESSABLE_ENTITY, and HTTP_URI_TOO_LONG.

Referenced by mapXrdErrToHttp().

+ Here is the caller graph for this function:

◆ mapXrdErrToHttp()

int mapXrdErrToHttp ( XErrorCode  xrdError)

Definition at line 514 of file XrdHttpUtils.cc.

514  {
515 
516  int errNo = XProtocol::toErrno(xrdError);
517  return mapErrNoToHttp(errNo);
518 
519 }
int mapErrNoToHttp(int errNo)
static int toErrno(int xerr)
Definition: XProtocol.hh:1453

References mapErrNoToHttp(), and XProtocol::toErrno().

+ Here is the call graph for this function:

◆ mystrchrnul()

char* mystrchrnul ( const char *  s,
int  c 
)

Definition at line 205 of file XrdHttpUtils.cc.

205  {
206  char *ptr = strchr((char *)s, c);
207 
208  if (!ptr)
209  return strchr((char *)s, '\0');
210 
211  return ptr;
212 }

◆ quote()

char* quote ( const char *  str)

Definition at line 414 of file XrdHttpUtils.cc.

414  {
415  int l = strlen(str);
416  char *r = (char *) malloc(l*3 + 1);
417  r[0] = '\0';
418  int i, j = 0;
419 
420  for (i = 0; i < l; i++) {
421  char c = str[i];
422 
423  switch (c) {
424  case ' ':
425  strcpy(r + j, "%20");
426  j += 3;
427  break;
428  case '[':
429  strcpy(r + j, "%5B");
430  j += 3;
431  break;
432  case ']':
433  strcpy(r + j, "%5D");
434  j += 3;
435  break;
436  case ':':
437  strcpy(r + j, "%3A");
438  j += 3;
439  break;
440  // case '/':
441  // strcpy(r + j, "%2F");
442  // j += 3;
443  // break;
444  case '#':
445  strcpy(r + j, "%23");
446  j += 3;
447  break;
448  case '\n':
449  strcpy(r + j, "%0A");
450  j += 3;
451  break;
452  case '\r':
453  strcpy(r + j, "%0D");
454  j += 3;
455  break;
456  case '=':
457  strcpy(r + j, "%3D");
458  j += 3;
459  break;
460  default:
461  r[j++] = c;
462  }
463  }
464 
465  r[j] = '\0';
466 
467  return r;
468 }

Referenced by encode_raw().

+ Here is the caller graph for this function:

◆ Tobase64() [1/2]

void Tobase64 ( const std::vector< uint8_t > &  input,
std::string &  base64Output 
)

Definition at line 90 of file XrdHttpUtils.cc.

90  {
91  BIO *bmem, *b64;
92  BUF_MEM *bptr;
93 
94  base64Output.clear();
95 
96  if(input.empty()) {
97  return;
98  }
99 
100  b64 = BIO_new(BIO_f_base64());
101  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
102  bmem = BIO_new(BIO_s_mem());
103  BIO_push(b64, bmem);
104  BIO_write(b64, input.data(), input.size());
105 
106  if (BIO_flush(b64) <= 0) {
107  BIO_free_all(b64);
108  return;
109  }
110 
111  BIO_get_mem_ptr(b64, &bptr);
112 
113  base64Output.assign(bptr->data,bptr->length);
114 
115  BIO_free_all(b64);
116 }

◆ Tobase64() [2/2]

void Tobase64 ( const unsigned char *  input,
int  length,
char *  out 
)

Definition at line 60 of file XrdHttpUtils.cc.

60  {
61  BIO *bmem, *b64;
62  BUF_MEM *bptr;
63 
64  if (!out) return;
65 
66  out[0] = '\0';
67 
68  b64 = BIO_new(BIO_f_base64());
69  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
70  bmem = BIO_new(BIO_s_mem());
71  BIO_push(b64, bmem);
72  BIO_write(b64, input, length);
73 
74  if (BIO_flush(b64) <= 0) {
75  BIO_free_all(b64);
76  return;
77  }
78 
79  BIO_get_mem_ptr(b64, &bptr);
80 
81 
82  memcpy(out, bptr->data, bptr->length);
83  out[bptr->length] = '\0';
84 
85  BIO_free_all(b64);
86 
87  return;
88 }

Referenced by calcHashes().

+ Here is the caller graph for this function:

◆ unquote()

char* unquote ( char *  str)

Definition at line 382 of file XrdHttpUtils.cc.

382  {
383  int l = strlen(str);
384  char *r = (char *) malloc(l + 1);
385  r[0] = '\0';
386  int i, j = 0;
387 
388  for (i = 0; i < l; i++) {
389  if (str[i] == '%') {
390  if (i + 3 > l) {
391  r[j] = '\0';
392  return r;
393  }
394  char savec = str[i + 3];
395  str[i + 3] = '\0';
396 
397  r[j] = strtol(str + i + 1, 0, 16);
398  str[i + 3] = savec;
399 
400  i += 2;
401  } else r[j] = str[i];
402 
403  j++;
404  }
405 
406  r[j] = '\0';
407 
408  return r;
409 
410 }

Referenced by decode_raw().

+ Here is the caller graph for this function: