-
Notifications
You must be signed in to change notification settings - Fork 65
/
Normalizer.java
143 lines (122 loc) · 4.75 KB
/
Normalizer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2011 Twitter, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
package com.twitter.joauth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* a Normalizer takes the fields that describe an OAuth 1.0a request, and produces
* the normalized string that is used for the signature.
*/
public abstract class Normalizer {
static final String HTTP = "HTTP";
static final String HTTPS = "HTTPS";
private static final StandardNormalizer STANDARD_NORMALIZER = new StandardNormalizer();
public static Normalizer getStandardNormalizer() {
return STANDARD_NORMALIZER;
}
public abstract String normalize(
String scheme,
String host,
int port,
String verb,
String path,
List<Request.Pair> params,
OAuthParams.OAuth1Params oAuth1Params
);
public String normalize(Request.ParsedRequest req, OAuthParams.OAuth1Params oAuth1Params) {
return normalize(
req.scheme(),
req.host(),
req.port(),
req.verb(),
req.path(),
req.params(),
oAuth1Params
);
}
/**
* the standard implementation of the Normalizer trait. Though stateless and threadsafe,
* this is a class rather than an object to allow easy access from Java. Scala codebases
* should use the corresponding STANDARD_NORMALIZER object instead.
*/
public static class StandardNormalizer extends Normalizer {
/* TODO: there is no way to clear string builder in java. see what can be done here.
Not using thread local.
private static final ThreadLocal<StringBuilder> builders = new ThreadLocal<StringBuilder>() {
@Override
protected StringBuilder initialValue() {
return new StringBuilder(512);
}
};
*/
@Override
public String normalize(
String scheme,
String host,
int port,
String verb,
String path,
List<Request.Pair> params,
OAuthParams.OAuth1Params oAuth1Params
) {
// We only need the stringbuilder for the duration of this method
StringBuilder paramsBuilder = new StringBuilder(512);
// first, concatenate the params and the oAuth1Params together.
// the parameters are already URLEncoded, so we leave them alone
ArrayList<Request.Pair> sigParams = new ArrayList<Request.Pair>();
sigParams.addAll(params);
sigParams.addAll(oAuth1Params.toList(false));
Collections.sort(sigParams, new Comparator<Request.Pair>() {
@Override
public int compare(Request.Pair thisPair, Request.Pair thatPair) {
// sort params first by key, then by value
int keyCompare = thisPair.key.compareTo(thatPair.key);
if (keyCompare == 0) {
return thisPair.value.compareTo(thatPair.value);
} else {
return keyCompare;
}
}
});
if (!sigParams.isEmpty()) {
Request.Pair head = sigParams.get(0);
paramsBuilder.append(head.key).append('=').append(head.value);
for (int i=1; i<sigParams.size(); i++) {
Request.Pair pair = sigParams.get(i);
paramsBuilder.append('&').append(pair.key).append('=').append(pair.value);
}
}
StringBuilder requestUrlBuilder = new StringBuilder(512);
requestUrlBuilder.append(scheme.toLowerCase());
requestUrlBuilder.append("://");
requestUrlBuilder.append(host.toLowerCase());
if (includePortString(port, scheme)) {
requestUrlBuilder.append(":").append(port);
}
requestUrlBuilder.append(path);
StringBuilder normalizedBuilder = new StringBuilder(512);
normalizedBuilder.append(verb.toUpperCase());
normalizedBuilder.append('&').append(UrlCodec.encode(requestUrlBuilder.toString()));
normalizedBuilder.append('&').append(UrlCodec.encode(paramsBuilder.toString()));
return normalizedBuilder.toString();
}
/**
* The OAuth 1.0a spec says that the port should not be included in the normalized string
* when (1) it is port 80 and the scheme is HTTP or (2) it is port 443 and the scheme is HTTPS
*/
boolean includePortString(int port, String scheme) {
return !((port == 80 && HTTP.equalsIgnoreCase(scheme)) || (port == 443 && HTTPS.equalsIgnoreCase(scheme)));
}
}
}