proxygen
Base64.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 #include <folly/Range.h>
13 #include <openssl/buffer.h>
14 
15 namespace {
16 struct BIODeleter {
17  public:
18  void operator()(BIO* bio) const { BIO_free_all(bio); };
19 };
20 
21 }
22 
23 namespace proxygen {
24 
25 // Decodes a base64url encoded string
26 std::string Base64::urlDecode(const std::string& urlB64message) {
27  std::unique_ptr<BIO, BIODeleter> bio, b64;
28  uint8_t padding = (4 - urlB64message.length() % 4) % 4;
29  if (padding == 3) {
30  return std::string();
31  }
32 
33  std::string b64message(urlB64message.length() + padding, 0);
35  urlB64message.begin(), urlB64message.end(), b64message.begin(),
36  [](char c) {
37  if (c == '-') {
38  return '+';
39  } else if (c == '_') {
40  return '/';
41  }
42  return c;
43  });
44  for (auto i = urlB64message.length(); i < urlB64message.length() + padding;
45  i++) {
46  b64message[i] = '=';
47  }
48  return decode(b64message, padding);
49 }
50 
51 std::string Base64::decode(const std::string& b64message, int padding) {
52  if (b64message.length() % 4 != 0 || padding >= 3) {
53  return std::string();
54  }
55 
56  std::unique_ptr<BIO, BIODeleter> bio, b64;
57  size_t decodeLen = b64message.length() * 3/4 - padding;
58  std::string result(decodeLen, '\0');
59 
60  bio.reset(BIO_new_mem_buf((void*)b64message.data(), -1));
61  if (!bio) {
62  return std::string();
63  }
64  b64.reset(BIO_new(BIO_f_base64()));
65  if (!b64) {
66  return std::string();
67  }
68  bio.reset(BIO_push(b64.release(), bio.release()));
69 
70  // Do not use newlines to flush buffer
71  BIO_set_flags(bio.get(), BIO_FLAGS_BASE64_NO_NL);
72  BIO_read(bio.get(), (char*)result.data(), b64message.length());
73  DCHECK_LE(result.length(), decodeLen);
74  if (result.length() < decodeLen) {
75  return std::string();
76  }
77  return result;
78 }
79 
81  std::unique_ptr<BIO, BIODeleter> bio, b64;
82  BUF_MEM* bufferPtr;
83 
84  b64.reset(BIO_new(BIO_f_base64()));
85  if (!b64) {
86  throw std::bad_alloc();
87  }
88  bio.reset(BIO_new(BIO_s_mem()));
89  if (!bio) {
90  throw std::bad_alloc();
91  }
92  bio.reset(BIO_push(b64.release(), bio.release()));
93 
94  // Ignore newlines - write everything in one line
95  BIO_set_flags(bio.get(), BIO_FLAGS_BASE64_NO_NL);
96  BIO_write(bio.get(), buffer.data(), buffer.size());
97  (void)BIO_flush(bio.get());
98  BIO_get_mem_ptr(bio.get(), &bufferPtr);
99  (void)BIO_set_close(bio.get(), BIO_NOCLOSE);
100 
101  std::string result(bufferPtr->data, bufferPtr->length);
102  BUF_MEM_free(bufferPtr);
103  return result;
104 }
105 
106 // Encodes a binary safe base 64 string
107 std::string Base64::urlEncode(folly::ByteRange buffer) {
108  std::string result = encode(buffer);
109  folly::StringPiece sp(result.data(), result.length());
110  uint8_t padding = 0;
112  sp.begin(), sp.end(), result.begin(),
113  [&padding](char c) {
114  if (c == '+') {
115  return '-';
116  } else if (c == '/') {
117  return '_';
118  } else if (c == '=') {
119  padding++;
120  }
121  return c;
122  });
123  DCHECK_LE(padding, result.length());
124  result.resize(result.length() - padding);
125  return result;
126 }
127 
128 }
std::vector< uint8_t > buffer(kBufferSize+16)
unique_ptr< IOBuf > encode(vector< HPACKHeader > &headers, HPACKEncoder &encoder)
TokenBindingMessage decode(folly::io::Cursor &cursor)
Definition: Types.cpp:132
constexpr size_type size() const
Definition: Range.h:431
PUSHMI_INLINE_VAR constexpr detail::transform_fn transform
Definition: transform.h:158
constexpr Iter data() const
Definition: Range.h:446
const char * string
Definition: Conv.cpp:212
char c