XRootD
Loading...
Searching...
No Matches
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)
char * vorg
Entity's virtual organization(s).
char * name
Entity's name.
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.

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()

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)

References char_to_int().

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:
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
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:
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
@ HTTP_INSUFFICIENT_STORAGE
@ HTTP_BAD_REQUEST
@ HTTP_LOOP_DETECTED
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_URI_TOO_LONG
@ HTTP_UNAUTHORIZED
@ HTTP_NOT_FOUND
@ HTTP_FORBIDDEN
@ HTTP_BAD_GATEWAY
@ HTTP_GATEWAY_TIMEOUT
@ HTTP_INTERNAL_SERVER_ERROR
@ HTTP_PAYLOAD_TOO_LARGE
@ HTTP_NOT_IMPLEMENTED
@ HTTP_UNPROCESSABLE_ENTITY
@ HTTP_CONFLICT

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)

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: