Skip to content

Instantly share code, notes, and snippets.

@danghica
Created June 27, 2019 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danghica/23b020b8125e1a050e860814b8d1623a to your computer and use it in GitHub Desktop.
Save danghica/23b020b8125e1a050e860814b8d1623a to your computer and use it in GitHub Desktop.
public final class XWWWFormUrlencodedHTTPRequest extends HashMap<String, String> {
private static final long serialVersionUID = 0xe673f874cf17d539L;
public XWWWFormUrlencodedHTTPRequest(URL url, Object... params)
throws IOException, IllegalArgumentException {
this(url, evenLengthListToMap(params));
}
@SuppressWarnings("LeakingThisInConstructor")
public XWWWFormUrlencodedHTTPRequest(URL url, Map<String, String> params)
throws IOException, MisencodedResponseException,
IllegalArgumentException {
super();
URLConnection c = url.openConnection();
if (!(c instanceof HttpURLConnection)) {
throw new IllegalArgumentException("URL " + url + " is not an HTTP URL");
}
HttpURLConnection hc = (HttpURLConnection) c;
hc.setDoOutput(true);
hc.setRequestMethod("POST");
hc.setRequestProperty("Content-Type", "x-www-form-urlencoded; charset=UTF-8");
hc.connect();
try {
try (OutputStream os = hc.getOutputStream()) {
os.write(urlEncodeMap(params).getBytes("UTF-8"));
}
switch (hc.getResponseCode()) {
case HttpURLConnection.HTTP_OK:
try (InputStream is = hc.getInputStream()) {
decodeInputStream(is, this);
} catch (XWWWFormUrlencodedHTTPHandler.HTTPResponseException ex) {
throw new MisencodedResponseException(ex.getCause());
}
break;
case HttpURLConnection.HTTP_NO_CONTENT:
case HttpURLConnection.HTTP_RESET:
/* These indicate success, but that no data was returned.
So we just continue to act as an empty map. */
break;
default:
throw new FailureOnServerException(hc.getResponseCode());
}
} finally {
hc.disconnect();
}
}
public String returnValue(String key) throws MisencodedResponseException {
if (containsKey(key)) {
return get(key);
} else {
throw new MisencodedResponseException(
"HTTP response did not contain key '" + key + "'");
}
}
public String nullableReturnValue(String isPresentKey, String valueKey)
throws MisencodedResponseException {
String isPresent = returnValue(isPresentKey);
switch (isPresent) {
case "true":
return returnValue(valueKey);
case "false":
return null;
default:
throw new MisencodedResponseException("Return value '"
+ isPresentKey + "' is neither 'true' nor 'false'");
}
}
@SuppressWarnings("UseSpecificCatch")
public <T, X extends Exception> T decodeReturnValue(
String key, XWWWFormUrlencodedHTTPHandler.ExceptionFunction<String, T, X> decoder,
Class<X> exception) throws MisencodedResponseException {
String param = returnValue(key);
try {
return decoder.apply(param);
} catch (RuntimeException ex) {
if (exception.isAssignableFrom(ex.getClass())) {
throw new MisencodedResponseException(
"Could not decode return value '" + key + "'", ex);
}
throw ex;
} catch (Exception ex) {
throw new MisencodedResponseException(
"Could not decode return value '" + key + "'", ex);
}
}
private static Map<String, String> evenLengthListToMap(Object[] list)
throws IllegalArgumentException {
Map<String, String> rv = new HashMap<>();
if ((list.length % 2) != 0) {
throw new IllegalArgumentException("list has odd length");
}
for (int i = 0; i < list.length; i += 2) {
if (list[i] instanceof String) {
rv.put((String) list[i], list[i + 1].toString());
} else {
throw new IllegalArgumentException("list element " + i
+ " is not a String");
}
}
return rv;
}
public static class FailureOnServerException extends IOException {
private static final long serialVersionUID = 0x89865f72fc9de35fL;
public FailureOnServerException(int code) {
super("HTTP connection failed with code " + code);
}
}
public static class MisencodedResponseException extends IOException {
private static final long serialVersionUID = 0x3799ea05e2f3f5f6L;
public MisencodedResponseException(Throwable cause) {
super(cause);
}
public MisencodedResponseException(String message) {
super(message);
}
public MisencodedResponseException(String message, Throwable cause) {
super(message, cause);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment