1/********************************************************************
2 * Copyright (c) 2013 - 2014, Pivotal Inc.
3 * All rights reserved.
4 *
5 * Author: Zhanwei Wang
6 ********************************************************************/
7/********************************************************************
8 * 2014 -
9 * open source under Apache License Version 2.0
10 ********************************************************************/
11/**
12 * Licensed to the Apache Software Foundation (ASF) under one
13 * or more contributor license agreements. See the NOTICE file
14 * distributed with this work for additional information
15 * regarding copyright ownership. The ASF licenses this file
16 * to you under the Apache License, Version 2.0 (the
17 * "License"); you may not use this file except in compliance
18 * with the License. You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28#include "Exception.h"
29#include "ExceptionInternal.h"
30#include "Hash.h"
31#include "Token.h"
32#include "WritableUtils.h"
33
34#include <gsasl.h>
35
36using namespace Hdfs::Internal;
37
38namespace Hdfs {
39namespace Internal {
40
41static std::string Base64Encode(const char * input, size_t len) {
42 int rc = 0;
43 size_t outLen;
44 char * output = NULL;
45 std::string retval;
46
47 if (GSASL_OK != (rc = gsasl_base64_to(input, len, &output, &outLen))) {
48 assert(GSASL_MALLOC_ERROR == rc);
49 throw std::bad_alloc();
50 }
51
52 assert(NULL != output);
53 retval = output;
54 gsasl_free(output);
55
56 for (size_t i = 0 ; i < retval.length(); ++i) {
57 switch (retval[i]) {
58 case '+':
59 retval[i] = '-';
60 break;
61
62 case '/':
63 retval[i] = '_';
64 break;
65
66 case '=':
67 retval.resize(i);
68 break;
69
70 default:
71 break;
72 }
73 }
74
75 return retval;
76}
77
78static void Base64Decode(const std::string & urlSafe,
79 std::vector<char> & buffer) {
80 int retval = 0, append = 0;
81 size_t outLen;
82 char * output = NULL;
83 std::string input = urlSafe;
84
85 for (size_t i = 0; i < input.length(); ++i) {
86 switch (input[i]) {
87 case '-':
88 input[i] = '+';
89 break;
90
91 case '_':
92 input[i] = '/';
93 break;
94
95 default:
96 break;
97 }
98 }
99
100 while (true) {
101 retval = gsasl_base64_from(&input[0], input.length(), &output, &outLen);
102
103 if (GSASL_OK != retval) {
104 switch (retval) {
105 case GSASL_BASE64_ERROR:
106 if (append++ < 2) {
107 input.append("=");
108 continue;
109 }
110
111 throw std::invalid_argument(
112 "invalid input of gsasl_base64_from");
113
114 case GSASL_MALLOC_ERROR:
115 throw std::bad_alloc();
116
117 default:
118 assert(
119 false
120 && "unexpected return value from gsasl_base64_from");
121 }
122 }
123
124 break;
125 }
126
127 assert(outLen >= 0);
128 buffer.resize(outLen);
129 memcpy(&buffer[0], output, outLen);
130 gsasl_free(output);
131}
132
133std::string Token::toString() const {
134 try {
135 size_t len = 0;
136 std::vector<char> buffer(1024);
137 WritableUtils out(&buffer[0], buffer.size());
138 len += out.WriteInt32(identifier.size());
139 len += out.WriteRaw(&identifier[0], identifier.size());
140 len += out.WriteInt32(password.size());
141 len += out.WriteRaw(&password[0], password.size());
142 len += out.WriteText(kind);
143 len += out.WriteText(service);
144 return Base64Encode(&buffer[0], len);
145 } catch (...) {
146 NESTED_THROW(HdfsIOException, "cannot convert token to string");
147 }
148}
149
150Token & Token::fromString(const std::string & str) {
151 int32_t len;
152
153 try {
154 std::vector<char> buffer;
155 Base64Decode(str, buffer);
156 WritableUtils in(&buffer[0], buffer.size());
157 len = in.ReadInt32();
158 identifier.resize(len);
159 in.ReadRaw(&identifier[0], len);
160 len = in.ReadInt32();
161 password.resize(len);
162 in.ReadRaw(&password[0], len);
163 kind = in.ReadText();
164 service = in.ReadText();
165 return *this;
166 } catch (...) {
167 NESTED_THROW(HdfsInvalidBlockToken,
168 "cannot construct a token from the string");
169 }
170}
171
172size_t Token::hash_value() const {
173 size_t values[] = { StringHasher(identifier), StringHasher(password),
174 StringHasher(kind), StringHasher(service)
175 };
176 return CombineHasher(values, sizeof(values) / sizeof(values[0]));
177}
178
179}
180}
181