Skip to content

Commit

Permalink
Merge pull request #140 from PasinduYeshan/feature/http-header
Browse files Browse the repository at this point in the history
Add http header feature to httpPost and httpGet methods
  • Loading branch information
Kanapriya authored Sep 7, 2023
2 parents f631a73 + 053e760 commit 06e2a6f
Show file tree
Hide file tree
Showing 12 changed files with 509 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up Adopt JDK 11
uses: actions/setup-java@v2
with:
java-version: "11"
java-version: [ 11.0.19+7 ]
distribution: "adopt"
- name: Cache local Maven repository
id: cache-maven-m2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,20 @@
</Export-Package>
<Import-Package>
javax.servlet.*; version="${imp.pkg.version.javax.servlet}",
org.apache.commons.collections,
org.apache.commons.io,
org.apache.commons.lang,
org.apache.commons.logging,
org.apache.http.entity,
org.apache.http.impl,
org.apache.http.util,
org.apache.http.client,
org.apache.http.client.entity,
org.apache.http.client.methods,
org.apache.http.client.config,
org.apache.http.impl.client,
org.apache.http.conn,
org.apache.http.message,
org.json.simple,
org.json.simple.parser,
org.apache.http,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.com).
* Copyright (c) 2021, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -20,6 +20,7 @@
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
Expand All @@ -42,14 +43,19 @@
import java.util.List;
import java.util.Map;

import static org.apache.http.HttpHeaders.ACCEPT;

/**
* Abstract class for handling http calls.
*/
public abstract class AbstractHTTPFunction {

private static final Log LOG = LogFactory.getLog(AbstractHTTPFunction.class);
protected static final String TYPE_APPLICATION_JSON = "application/json";
protected static final String TYPE_APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";
protected static final String TYPE_TEXT_PLAIN = "text/plain";
private static final char DOMAIN_SEPARATOR = '.';
private static final String RESPONSE = "response";
private final List<String> allowedDomains;

private CloseableHttpClient client;
Expand All @@ -73,15 +79,15 @@ protected void executeHttpMethod(HttpUriRequest request, Map<String, Object> eve
JSONObject json = null;
int responseCode;
String outcome;
String epUrl = null;
String endpointURL = null;

if (request.getURI() != null) {
epUrl = request.getURI().toString();
endpointURL = request.getURI().toString();
}

if (!isValidRequestDomain(request.getURI())) {
outcome = Constants.OUTCOME_FAIL;
LOG.error("Provided Url does not contain a allowed domain. Invalid Url: " + epUrl);
LOG.error("Provided Url does not contain a allowed domain. Invalid Url: " + endpointURL);
asyncReturn.accept(context, Collections.emptyMap(), outcome);
return;
}
Expand All @@ -90,21 +96,30 @@ protected void executeHttpMethod(HttpUriRequest request, Map<String, Object> eve
responseCode = response.getStatusLine().getStatusCode();
if (responseCode >= 200 && responseCode < 300) {
outcome = Constants.OUTCOME_SUCCESS;
String jsonString = EntityUtils.toString(response.getEntity());
JSONParser parser = new JSONParser();
json = (JSONObject) parser.parse(jsonString);
if (response.getEntity() != null) {
Header contentType = response.getEntity().getContentType();
String jsonString = EntityUtils.toString(response.getEntity());
if (contentType != null && contentType.getValue().contains(TYPE_TEXT_PLAIN)) {
// For 'text/plain', put the response body into the JSON object as a single field.
json = new JSONObject();
json.put(RESPONSE, jsonString);
} else {
JSONParser parser = new JSONParser();
json = (JSONObject) parser.parse(jsonString);
}
}
} else {
outcome = Constants.OUTCOME_FAIL;
}

} catch (IllegalArgumentException e) {
LOG.error("Invalid Url: " + epUrl, e);
LOG.error("Invalid Url: " + endpointURL, e);
outcome = Constants.OUTCOME_FAIL;
} catch (ConnectTimeoutException e) {
LOG.error("Error while waiting to connect to " + epUrl, e);
LOG.error("Error while waiting to connect to " + endpointURL, e);
outcome = Constants.OUTCOME_TIMEOUT;
} catch (SocketTimeoutException e) {
LOG.error("Error while waiting for data from " + epUrl, e);
LOG.error("Error while waiting for data from " + endpointURL, e);
outcome = Constants.OUTCOME_TIMEOUT;
} catch (IOException e) {
LOG.error("Error while calling endpoint. ", e);
Expand Down Expand Up @@ -172,4 +187,35 @@ private String getParentDomainFromUrl(URI url) {
}
return parentDomain;
}

/**
* Validate the headers.
*
* @param headers Map of headers.
* @return Map of headers.
*/
protected Map<String, String> validateHeaders(Map<String, ?> headers) {

for (Map.Entry<String, ?> entry : headers.entrySet()) {
if (!(entry.getValue() instanceof String)) {
throw new IllegalArgumentException("Header values must be of type String");
}
}
return (Map<String, String>) headers;
}

/**
* Set headers to the request.
* Default Accept header is set to application/json.
*
* @param request HttpUriRequest.
* @param headers Map of headers.
*/
protected void setHeaders(HttpUriRequest request, Map<String, String> headers) {

headers.putIfAbsent(ACCEPT, TYPE_APPLICATION_JSON);
headers.entrySet().stream()
.filter(entry -> StringUtils.isNotBlank(entry.getKey()) && !entry.getKey().equals("null"))
.forEach(entry -> request.setHeader(entry.getKey(), entry.getValue()));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -29,8 +29,10 @@ public interface HTTPGetFunction {
/**
* POST data to the given endpoint.
*
* @param epUrl Endpoint url.
* @param eventHandlers event handlers.
* @param endpointURL Endpoint url.
* @param params Parameters.
* 1. headers headers (optional).
* 2. eventHandlers event handlers.
*/
void httpGet(String epUrl, Map<String, Object> eventHandlers);
void httpGet(String endpointURL, Object... params);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -18,10 +18,12 @@

package org.wso2.carbon.identity.conditional.auth.functions.http;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpGet;

import java.util.HashMap;
import java.util.Map;

import static org.apache.http.HttpHeaders.ACCEPT;
Expand All @@ -39,10 +41,37 @@ public HTTPGetFunctionImpl() {
}

@Override
public void httpGet(String epUrl, Map<String, Object> eventHandlers) {
public void httpGet(String endpointURL, Object... params) {

Map<String, Object> eventHandlers;
Map<String, String> headers = new HashMap<>();

switch (params.length) {
case 1:
if (params[0] instanceof Map) {
eventHandlers = (Map<String, Object>) params[0];
} else {
throw new IllegalArgumentException("Invalid argument type. Expected eventHandlers " +
"(Map<String, Object>).");
}
break;
case 2:
if (params[0] instanceof Map && params[1] instanceof Map ) {
headers = validateHeaders((Map<String, ?>) params[0]);
eventHandlers = (Map<String, Object>) params[1];
} else {
throw new IllegalArgumentException("Invalid argument types. Expected headers (Map<String, String>) " +
"and eventHandlers (Map<String, Object>) respectively.");
}
break;
default:
throw new IllegalArgumentException("Invalid number of arguments. Expected 1 or 2, but got: " +
params.length + ".");
}

HttpGet request = new HttpGet(endpointURL);
setHeaders(request, headers);

HttpGet request = new HttpGet(epUrl);
request.setHeader(ACCEPT, TYPE_APPLICATION_JSON);
executeHttpMethod(request, eventHandlers);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -30,9 +30,11 @@ public interface HTTPPostFunction {
/**
* POST data to the given endpoint.
*
* @param epUrl Endpoint url.
* @param payloadData payload data.
* @param eventHandlers event handlers.
* @param endpointURL Endpoint url.
* @param params parameters.
* 1. payloadData payload data.
* 2. headers headers (optional).
* 3. eventHandlers event handlers.
*/
void httpPost(String epUrl, Map<String, Object> payloadData, Map<String, Object> eventHandlers);
void httpPost(String endpointURL, Object... params);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -18,13 +18,21 @@

package org.wso2.carbon.identity.conditional.auth.functions.http;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.json.simple.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.http.HttpHeaders.ACCEPT;
Expand All @@ -44,17 +52,68 @@ public HTTPPostFunctionImpl() {
}

@Override
public void httpPost(String epUrl, Map<String, Object> payloadData, Map<String, Object> eventHandlers) {
public void httpPost(String endpointURL, Object... params) {

HttpPost request = new HttpPost(epUrl);
request.setHeader(ACCEPT, TYPE_APPLICATION_JSON);
request.setHeader(CONTENT_TYPE, TYPE_APPLICATION_JSON);
Map<String, Object> eventHandlers;
Map<String, Object> payloadData = new HashMap<>();
Map<String, String> headers = new HashMap<>();

JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, Object> dataElements : payloadData.entrySet()) {
jsonObject.put(dataElements.getKey(), dataElements.getValue());
switch (params.length) {
case 1:
if (params[0] instanceof Map) {
eventHandlers = (Map<String, Object>) params[0];
} else {
throw new IllegalArgumentException("Invalid argument type. Expected eventHandlers " +
"(Map<String, Object>).");
}
break;
case 2:
if (params[0] instanceof Map && params[1] instanceof Map) {
payloadData = (Map<String, Object>) params[0];
eventHandlers = (Map<String, Object>) params[1];
} else {
throw new IllegalArgumentException("Invalid argument types. Expected payloadData and eventHandlers " +
"(both of type Map<String, Object>) respectively.");
}
break;
case 3:
if (params[0] instanceof Map && params[1] instanceof Map && params[2] instanceof Map) {
payloadData = (Map<String, Object>) params[0];
headers = validateHeaders((Map<String, ?>) params[1]);
eventHandlers = (Map<String, Object>) params[2];
} else {
throw new IllegalArgumentException("Invalid argument type. Expected payloadData " +
"(Map<String, Object>), headers (Map<String, String>), and eventHandlers " +
"(Map<String, Object>) respectively.");
}
break;
default:
throw new IllegalArgumentException("Invalid number of arguments. Expected 1, 2, or 3. Found: "
+ params.length + ".");
}

HttpPost request = new HttpPost(endpointURL);
headers.putIfAbsent(CONTENT_TYPE, TYPE_APPLICATION_JSON);
setHeaders(request, headers);

if (MapUtils.isNotEmpty(payloadData)) {
/*
For the header "Content-Type : application/x-www-form-urlencoded" request body data is set to
UrlEncodedFormEntity format. For the other cases request body data is set to StringEntity format.
*/
if (TYPE_APPLICATION_FORM_URLENCODED.equals(headers.get(CONTENT_TYPE))) {
List<NameValuePair> entities = new ArrayList<>();
for (Map.Entry<String, Object> dataElements : payloadData.entrySet()) {
String value = (dataElements.getValue() != null) ? dataElements.getValue().toString() : null;
entities.add(new BasicNameValuePair(dataElements.getKey(), value));
}
request.setEntity(new UrlEncodedFormEntity(entities, StandardCharsets.UTF_8));
} else {
JSONObject jsonObject = new JSONObject();
jsonObject.putAll(payloadData);
request.setEntity(new StringEntity(jsonObject.toJSONString(), StandardCharsets.UTF_8));
}
request.setEntity(new StringEntity(jsonObject.toJSONString(), StandardCharsets.UTF_8));
executeHttpMethod(request, eventHandlers);
}
executeHttpMethod(request, eventHandlers);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down
Loading

0 comments on commit 06e2a6f

Please sign in to comment.