I have create Java Classes from the DHL WSDL
https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/2.2/geschaeftskundenversand-api-2.2.wsdl.
Now i have all Classes, but no Authentifaction Class.
I try this
GKVAPIServicePortTypeProxy port2 = new GKVAPIServicePortTypeProxy();
port2.setEndpoint("https://cig.dhl.de/services/sandbox/soap");
CreateShipmentOrderRequest sh = new CreateShipmentOrderRequest();
//Setting up shipment;
.. and so on
CreateShipmentOrderResponse chr = port2.createShipmentOrder(sh);
But only what i get is, "(401)Authorization Required"
How can i set my Authentifiaction ?
Hi I h had fixed the 401 problem with adding of the ssl certificate from DHL to my application truststore.
But I have the problem that I missing to add the Authentification block to the request.
<soapenv:Header>
<cis:Authentification>
<cis:user>user</cis:user>
<cis:signature>password</cis:signature>
</cis:Authentification>
</soapenv:Header>
My try to adding this block resulting in a 'org.quartz.jobexecutionexception: de.vps.icms.exceptions.icmsscriptingexception: java.lang.noclassdeffounderror: org/apache/axis2/saaj/soapenvelopeimpl'exception.
Some idea what I did wrong?
Here the Code:
public class WSClient {
public WSClient() {
try {
GKVAPIServicePortType port = prepareService();
String b = BWIConstants.SYSPARAM_DHL_WS_URL;
CreateShipmentOrderRequest createShipmentOrderRequest = new CreateShipmentOrderRequest();
CreateShipmentOrderResponse createShipmentOrderResponse =
port.createShipmentOrder(createShipmentOrderRequest);
createShipmentOrderResponse.getStatus();
} catch (Exception e) {
e.printStackTrace();
}
}
private GKVAPIServicePortType prepareService() throws MalformedURLException {
// get Service stub
String pathToClassFolder = getClass().getResource("/").toString();
String fullwsdlFilePath = pathToClassFolder + "/" + "geschaeftskundenversand-api-2.2.wsdl";
URL wsdlLocation = new URL(fullwsdlFilePath);
GVAPI20De service = new GVAPI20De(wsdlLocation);
// get Service Port
GKVAPIServicePortType port = service.getPort(GKVAPIServicePortType.class);
// overwrite Endpoint
Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://cig.dhl.de/services/sandbox/soap");
// overwrite BasicAuth Username and Password
// requestContext.put(BindingProvider.USERNAME_PROPERTY, cigUser);
// requestContext.put(BindingProvider.PASSWORD_PROPERTY, cigPass);
// Add authentication Handler
Binding binding = ((BindingProvider) port).getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add(
new AuthenticationHandler(BWIConstants.SYSPARAM_DHL_WS_USER, BWIConstants.SYSPARAM_DHL_WS_SIGNATURE));
binding.setHandlerChain(handlerChain);
return port;
}
}
public class AuthenticationHandler implements SOAPHandler<SOAPMessageContext> {
private String USER = "";
private String PASSWORD = "";
public AuthenticationHandler(final String user, final String password) {
USER = user;
PASSWORD = password;
}
/**
* {#inheritDoc}
*/
public void close(final MessageContext context) {
// nothing to do
}
/**
* {#inheritDoc}
*/
public Set<QName> getHeaders() {
// nothing to do
return null;
}
/**
* {#inheritDoc}
*/
public boolean handleFault(final SOAPMessageContext context) {
// nothing to do
return true;
}
/**
* {#inheritDoc}
*/
public boolean handleMessage(final SOAPMessageContext context) {
if (isOutboundMessage(context)) {
try {
// get/create the map of HTTP headers
Map<Object, Object> headers = (Map<Object, Object>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<Object, Object>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
// add custom HTTP header (deactivate HTTP keepAlive)
String headerName = "Connection";
List<String> headerValues = new ArrayList<String>();
headerValues.add("Close");
headers.put(headerName, headerValues);
SOAPMessage message = context.getMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPHeader header;
if (envelope.getHeader() == null) {
header = envelope.addHeader();
} else {
header = envelope.getHeader();
}
// add the Authentification element
SOAPElement auth = header.addHeaderElement(
envelope.createName("Authentification", "cis", "http://dhl.de/webservice/cisbase"));
SOAPElement user =
auth.addChildElement(envelope.createName("user", "cis", "http://dhl.de/webservice/cisbase"));
user.setValue(USER);
SOAPElement signature =
auth.addChildElement(envelope.createName("signature", "cis", "http://dhl.de/webservice/cisbase"));
signature.setValue(PASSWORD);
SOAPElement type =
auth.addChildElement(envelope.createName("type", "cis", "http://dhl.de/webservice/cisbase"));
type.setValue("0");
// save changes
message.saveChanges();
} catch (SOAPException ex) {
throw new RuntimeException("Failed to add SOAP headers for authentication.", ex);
}
}
return true;
}
private boolean isOutboundMessage(final MessageContext context) {
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
return outboundProperty.booleanValue();
}
}
Using basic authentication, you would first Base64 encode your username:password - there's online sites that will do it but beware as likely not a good idea to do it if it refers to DHL in anyway, e.g. they could swipe your credentials.
You then get the Request Context of the port, create a map of the headers and add an Authorization header. Finally you add that back to the request context.
Example:
Note, I purposely generated bad base64 encoding so you would likely not be able to decode it and see it properly formatted with the "username:password"
GVAPI20De service1 = new GVAPI20De();
GKVAPIServicePortType port2 = service1.getGKVAPISOAP11Port0();
CreateShipmentOrderRequest sh = new CreateShipmentOrderRequest();
//Setting up shipment;
Map<String, Object> req_ctx = ((BindingProvider)port2).getRequestContext();
//you may not need this and can try commenting it out
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/2.2/geschaeftskundenversand-api-2.2.wsdl");
//optional timeout
req_ctx.put("javax.xml.ws.client.connectionTimeout", "60000");
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Authorization", Collections.singletonList("Basic c3gh567sd4689k11lg=="));
req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
CreateShipmentOrderResponse chr = port2.createShipmentOrder(sh)
Related
I'm trying to access/read headers from WebServiceContext on the web service method after execution by the SOAP handler, but I get an exception:
java.lang.RuntimeException: DOMStreamReader: getElementText() not implemented
at com.sun.xml.ws.streaming.DOMStreamReader.getElementText(DOMStreamReader.java:401) ~[jaxws-rt.jar:2.3.2]
If I don't execute the SOAP handler, I can read header values during web service execution.
Web Services Class
#WebService(targetNamespace = "http://example.com/LOGIN", serviceName = "UserLogin")
#HandlerChain(file = "../handlers.xml")
public class LoginImpl {
#Resource
WebServiceContext context;
(...)
#WebMethod(operationName = "Suspend", action = "http://example.com/LOGIN/Suspend")
#WebResult(name = "SuspendResult", targetNamespace = "http://example.com/LOGIN")
#RequestWrapper(targetNamespace = "http://example.com/LOGIN")
#ResponseWrapper(targetNamespace = "http://example.com/LOGIN")
public WSResult suspend(
#WebParam(name = "user", targetNamespace = "http://example.com/LOGIN") String userid) {
HeaderList hl = (HeaderList) context.getMessageContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
if (hl != null) {
Header cred = hl.get(new QName("http://example.com/definitions","Credentials"), true);
if (cred != null) {
try {
WSCredentials result = new WSCredentials();
result.roles = new HashSet<String>();
XMLStreamReader reader = cred.readHeader();
int eventType = reader.getEventType();
do {
if (eventType == XMLStreamConstants.START_ELEMENT) {
if ("Username".equals(reader.getLocalName())) {
String text = reader.getElementText(); // -> java.lang.RuntimeException: DOMStreamReader
result.username = text;
}
(...)
}
(...)
SOAP Handler
public class ValidateAuthorization implements SOAPHandler<SOAPMessageContext> {
public ValidateAuthorization() {
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
if (Boolean.FALSE.equals(context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY))) {
String username = null;
try {
SOAPMessage soapMessage = context.getMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader header = soapEnvelope.getHeader();
WSCredentials result = new WSCredentials();
result.roles = new HashSet<String>();
Iterator<?> headerElements = header.examineAllHeaderElements();
while (headerElements.hasNext()) {
SOAPHeaderElement headerElement = (SOAPHeaderElement) headerElements.next();
if (headerElement.getElementName().getLocalName().equals("Credentials")) {
SOAPHeaderElement securityElement = headerElement;
Iterator<?> it2 = securityElement.getChildElements();
while (it2.hasNext()) {
Node soapNode = (Node) it2.next();
if (soapNode instanceof SOAPElement) {
SOAPElement element = (SOAPElement) soapNode;
QName elementQname = element.getElementQName();
if(elementQname.getLocalPart().equals("Username")) {
username = element.getValue();
result.username = element.getValue();
}
}
}
}
}
soapMessage.writeTo(System.out);
log.debug("USERNAME " + username); // OK!
} catch (Exception e) {
log.error("Error reading SOAP message context: " + e, e);
e.printStackTrace();
}
}
return true;
}
(...)
}
I would like to read SOAPEnv headers on SOAP handlers and on web service execution. I suspect that the first iteration over the list of headers changes the pointer to the XLM of the web service, which does not allow the correct reading in the second iteration.
To observe this behavior, just access the headers in the SOAP Handler, even without iterating over them. That is, it suffices that the SOAPHeader object be created in the
public class ValidateAuthorization implements SOAPHandler<SOAPMessageContext> method, so that I cannot read the headers when executing the web service.
SOAPMessage soapMessage = context.getMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader header = soapEnvelope.getHeader();
If I don't access the SOAP Headers in the SOAP Handler, I can list the headers in the web service.
Could you help me, please? Many thanks.
I have a wsdl from ERP cloud. To consume it in Java, I compiled it using wsimport and extracted all the java files.
Now I'm trying to use these java files in order to communicate to the server data through wsdl. The wsdl requires authentication.
Problem
Whenever I try to run my custom code to connect to wsdl, for authentication it works with simple setting of username and password in Binding context.
private void attachAuthentication(Object className) {
BindingProvider prov = (BindingProvider) className;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "xxx");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "xxx");
}
But whenever I deploy my code on a weblogic GPI instance, it gives me following error.
com.sun.xml.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: The request was invalid or malformed Please see the server log to find more detail regarding exact cause of the failure.
at com.sun.xml.ws.fault.SOAP12Fault.getProtocolException(SOAP12Fault.java:229)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:139)
at com.sun.xml.ws.client.sei.StubHandler.readResponse(StubHandler.java:253)
at com.sun.xml.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:203)
at com.sun.xml.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:290)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
I tried attaching a Soap handler to my SEI. Here's what I've done.
InitializeErp.java
HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver();
InvoiceInterfaceService_Service interfaceInvoice = new InvoiceInterfaceService_Service();
interfaceInvoice.setHandlerResolver(handlerResolver);
invoiceInterfaceServiceSoapHttpPort = interfaceInvoice.getInvoiceInterfaceServiceSoapHttpPort();
HeaderHandlerResolver.java
public class HeaderHandlerResolver implements HandlerResolver {
#Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
HandlerHeader hh = new HandlerHeader();
handlerChain.add(hh);
return handlerChain;
}
}
HeaderHandler.java
public class HandlerHeader implements SOAPHandler<SOAPMessageContext> {
#Override
public Set<QName> getHeaders() {
return Collections.emptySet();
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
final Boolean outInd = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outInd) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.mmm'Z'");
Date creationDate = new Date();
Date expirationDate = new Date(creationDate.getTime() + TimeUnit.HOURS.toMillis(1));
try {
SOAPMessage message = context.getMessage();
SOAPEnvelope env = message.getSOAPPart().getEnvelope();
env.addNamespaceDeclaration("sch", "http://xmlns.oracle.com/scheduler");
env.addNamespaceDeclaration("typ", "http://xmlns.oracle.com/scheduler/types");
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
env.removeNamespaceDeclaration("SOAP-ENV");
env.setPrefix("soapenv");
header.setPrefix("soapenv");
body.setPrefix("soapenv");
QName security = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "wsse");
// Constructing Header
SOAPElement securityElement = header.addChildElement(security);
securityElement.addNamespaceDeclaration("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
securityElement.setAttribute("soapenv:mustUnderstand", "1");
QName usernameToken = new QName("UsernameToken", "wsse");
SOAPElement usernameTokenElement = securityElement.addChildElement("UsernameToken", "wsse");
usernameTokenElement.setAttribute("wsu:Id", "UsernameToken-97B1FF404874F4997215144527824364");
QName username = new QName("Username", "wsse");
SOAPElement usernameElement = usernameTokenElement.addChildElement("Username", "wsse");
usernameElement.addTextNode("xxx");
QName passwrod = new QName("Password", "wsse");
SOAPElement passwordElement = usernameTokenElement.addChildElement("Password", "wsse");
passwordElement.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElement.addTextNode("xxx");
QName nonce = new QName("Nonce", "wsse");
SOAPElement nonceElement = usernameTokenElement.addChildElement("Nonce", "wsse");
nonceElement.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
nonceElement.addTextNode("Ox0BI3sh1pPSe2S7NsUzeg==");
QName created = new QName("Created", "wsu");
SOAPElement createdElement = usernameTokenElement.addChildElement("Created", "wsu");
createdElement.addTextNode(format.format(creationDate));
QName timestamp = new QName("Timestamp", "wsu");
SOAPElement timestampElement = securityElement.addChildElement("Timestamp", "wsu");
timestampElement.setAttribute("wsu:Id", "TS-4");
QName createdTimestamp = new QName("Created", "wsu");
SOAPElement createdTimestampElement = timestampElement.addChildElement("Created", "wsu");
createdTimestampElement.addTextNode(format.format(creationDate));
QName expiresTimestamp = new QName("Expires", "wsu");
SOAPElement expiresTimestampElement = timestampElement.addChildElement("Expires", "wsu");
expiresTimestampElement.addTextNode(format.format(expirationDate));
// Print out the outbound SOAP message to System.out
System.out.println("setting attributes...");
message.writeTo(System.out);
System.out.println("");
System.out.println("message printed..");
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
try {
SOAPMessage message = context.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
String strMsg = new String(out.toByteArray());
RequestFilter.getSession().setAttribute("soap fault", "Soap ->" + strMsg);
} catch (SOAPException | IOException ex) {
RequestFilter.getSession().setAttribute("mailContent", ex.toString());
}
return true;
}
#Override
public void close(MessageContext context) {
}
}
This is what my Soap HEader looks like.
On running it on server. This is what I get in my SoapFault
Soap -> ns1:Senderns2:InvalidRequestThe request was invalid or malformedweblogic.wsee.security.wst.faults.InvalidRequestException: Server Authentication Required at weblogic.wsee.security.wst.framework.TrustSoapClient.invoke(TrustSoapClient.java:157) at weblogic.wsee.security.wst.framework.TrustSoapClient.requestTrustToken(TrustSoapClient.java:110) at weblogic.wsee.security.saml.SAMLTrustCredentialProvider.createCredential(SAMLTrustCredentialProvider.java:432) at
I've many ways to modify the Soap header, Removed security, just passed username password, Added both handler as well as credentials in BindingContext, But nothing seems to work on server.
With the header attached, I get the following error on local
I'm out of ways now. Can anyone please suggest me any approach or point out what am I missing. What should I try now. Any help is appreciated. All suggestions are welcome.
I use okhttp to be my httpclient. I think it's a good api but the doc is not so detailed.
how to use it to make a http post request with file uploading?
public Multipart createMultiPart(File file){
Part part = (Part) new Part.Builder().contentType("").body(new File("1.png")).build();
//how to set part name?
Multipart m = new Multipart.Builder().addPart(part).build();
return m;
}
public String postWithFiles(String url,Multipart m) throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
m.writeBodyTo(out)
;
Request.Body body = Request.Body.create(MediaType.parse("application/x-www-form-urlencoded"),
out.toByteArray());
Request req = new Request.Builder().url(url).post(body).build();
return client.newCall(req).execute().body().string();
}
my question is:
how to set part name? in the form, the file should be named file1.
how to add other fields in the form?
Here is a basic function that uses okhttp to upload a file and some arbitrary field (it literally simulates a regular HTML form submission)
Change the mime type to match your file (here I am assuming .csv) or make it a parameter to the function if you are going to upload different file types
public static Boolean uploadFile(String serverURL, File file) {
try {
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("text/csv"), file))
.addFormDataPart("some-field", "some-value")
.build();
Request request = new Request.Builder()
.url(serverURL)
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(final Call call, final IOException e) {
// Handle the error
}
#Override
public void onResponse(final Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
// Handle the error
}
// Upload successful
}
});
return true;
} catch (Exception ex) {
// Handle the error
}
return false;
}
Note: because it is async call, the boolean return type does not indicate successful upload but only that the request was submitted to okhttp queue.
Here's an answer that works with OkHttp 3.2.0:
public void upload(String url, File file) throws IOException {
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("text/plain"), file))
.addFormDataPart("other_field", "other_field_value")
.build();
Request request = new Request.Builder().url(url).post(formBody).build();
Response response = client.newCall(request).execute();
}
Note: this answer is for okhttp 1.x/2.x. For 3.x, see this other answer.
The class Multipart from mimecraft encapsulates the whole HTTP body and can handle regular fields like so:
Multipart m = new Multipart.Builder()
.type(Multipart.Type.FORM)
.addPart(new Part.Builder()
.body("value")
.contentDisposition("form-data; name=\"non_file_field\"")
.build())
.addPart(new Part.Builder()
.contentType("text/csv")
.body(aFile)
.contentDisposition("form-data; name=\"file_field\"; filename=\"file1\"")
.build())
.build();
Take a look at examples of multipart/form-data encoding to get a sense of how you need to construct the parts.
Once you have a Multipart object, all that's left to do is specify the right Content-Type header and pass on the body bytes to the request.
Since you seem to be working with the v2.0 of the OkHttp API, which I don't have experience with, this is just guess code:
// You'll probably need to change the MediaType to use the Content-Type
// from the multipart object
Request.Body body = Request.Body.create(
MediaType.parse(m.getHeaders().get("Content-Type")),
out.toByteArray());
For OkHttp 1.5.4, here is a stripped down code I'm using which is adapted from a sample snippet:
OkHttpClient client = new OkHttpClient();
OutputStream out = null;
try {
URL url = new URL("http://www.example.com");
HttpURLConnection connection = client.open(url);
for (Map.Entry<String, String> entry : multipart.getHeaders().entrySet()) {
connection.addRequestProperty(entry.getKey(), entry.getValue());
}
connection.setRequestMethod("POST");
// Write the request.
out = connection.getOutputStream();
multipart.writeBodyTo(out);
out.close();
// Read the response.
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Unexpected HTTP response: "
+ connection.getResponseCode() + " " + connection.getResponseMessage());
}
} finally {
// Clean up.
try {
if (out != null) out.close();
} catch (Exception e) {
}
}
I've created cool helper class for OkHttp3. it here
public class OkHttp3Helper {
public static final String TAG;
private static final okhttp3.OkHttpClient client;
static {
TAG = OkHttp3Helper.class.getSimpleName();
client = new okhttp3.OkHttpClient.Builder()
.readTimeout(7, TimeUnit.MINUTES)
.writeTimeout(7, TimeUnit.MINUTES)
.build();
}
private Context context;
public OkHttp3Helper(Context context) {
this.context = context;
}
/**
* <strong>Uses:</strong><br/>
* <p>
* {#code
* ArrayMap<String, String> formField = new ArrayMap<>();}
* <br/>
* {#code formField.put("key1", "value1");}<br/>
* {#code formField.put("key2", "value2");}<br/>
* {#code formField.put("key3", "value3");}<br/>
* <br/>
* {#code String response = helper.postToServer("http://www.example.com/", formField);}<br/>
* </p>
*
* #param url String
* #param formField android.support.v4.util.ArrayMap
* #return response from server in String format
* #throws Exception
*/
#NonNull
public String postToServer(#NonNull String url, #Nullable ArrayMap<String, String> formField)
throws Exception {
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
if (formField != null) {
okhttp3.FormBody.Builder formBodyBuilder = new okhttp3.FormBody.Builder();
for (Map.Entry<String, String> entry : formField.entrySet()) {
formBodyBuilder.add(entry.getKey(), entry.getValue());
}
requestBuilder.post(formBodyBuilder.build());
}
okhttp3.Request request = requestBuilder.build();
okhttp3.Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException(response.message());
}
return response.body().string();
}
/**
* <strong>Uses:</strong><br/>
* <p>
* {#code
* ArrayMap<String, String> formField = new ArrayMap<>();}
* <br/>
* {#code formField.put("key1", "value1");}<br/>
* {#code formField.put("key2", "value2");}<br/>
* {#code formField.put("key3", "value3");}<br/>
* <br/>
* {#code
* ArrayMap<String, File> filePart = new ArrayMap<>();}
* <br/>
* {#code filePart.put("key1", new File("pathname"));}<br/>
* {#code filePart.put("key2", new File("pathname"));}<br/>
* {#code filePart.put("key3", new File("pathname"));}<br/>
* <br/>
* {#code String response = helper.postToServer("http://www.example.com/", formField, filePart);}<br/>
* </p>
*
* #param url String
* #param formField android.support.v4.util.ArrayMap
* #param filePart android.support.v4.util.ArrayMap
* #return response from server in String format
* #throws Exception
*/
#NonNull
public String postMultiPartToServer(#NonNull String url,
#Nullable ArrayMap<String, String> formField,
#Nullable ArrayMap<String, File> filePart)
throws Exception {
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
if (formField != null || filePart != null) {
okhttp3.MultipartBody.Builder multipartBodyBuilder = new okhttp3.MultipartBody.Builder();
multipartBodyBuilder.setType(okhttp3.MultipartBody.FORM);
if (formField != null) {
for (Map.Entry<String, String> entry : formField.entrySet()) {
multipartBodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
}
}
if (filePart != null) {
for (Map.Entry<String, File> entry : filePart.entrySet()) {
File file = entry.getValue();
multipartBodyBuilder.addFormDataPart(
entry.getKey(),
file.getName(),
okhttp3.RequestBody.create(getMediaType(file.toURI()), file)
);
}
}
requestBuilder.post(multipartBodyBuilder.build());
}
okhttp3.Request request = requestBuilder.build();
okhttp3.Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException(response.message());
}
return response.body().string();
}
private okhttp3.MediaType getMediaType(URI uri1) {
Uri uri = Uri.parse(uri1.toString());
String mimeType;
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
ContentResolver cr = context.getContentResolver();
mimeType = cr.getType(uri);
} else {
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
.toString());
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
fileExtension.toLowerCase());
}
return okhttp3.MediaType.parse(mimeType);
}
}
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(180, TimeUnit.SECONDS).readTimeout(180, TimeUnit.SECONDS).build();
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("File", path.getName(),RequestBody.create(MediaType.parse("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),path))
.addFormDataPart("username", username)
.addFormDataPart("password", password)
.build();
Request request = new Request.Builder().url(url).post(body).build();
Response response = client.newCall(request).execute();
result = response.body().string();
Above code will send the username, password as the post parameter and the file will be uploaded in the name of "File".
PHP Server will receive the files
if (isset($_FILES["File"]) &&
isset($_POST['username']) &&
isset($_POST['password'])) {
//All Values found
}else{
echo 'please send the required data';
}
Perfect code for uploading any files to google drive along with metadata of files easily.
String url = String.format("https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart");
//String url = String.format("https://www.googleapis.com/upload/drive/v2/files?uploadType=resumable");
boolean status;
String metaDataFile = "{\"title\":\"" + step.getFile_name() + "\"," +
"\"description\":\"" + step.getDescription() + "\"," +
"\"parents\":[{\"id\":\"" + step.getFolderId() + "\"}]," +
"\"capabilities\":{\"canEdit\":\"" + false + "\", \"canDownload\":\" "+ false +" \" }, " +
"\"type\":\"" + step.getFile_access() + "\"" +
"}";
//get the encoded byte data for decode
byte[] file = Base64.decodeBase64(step.getFile_data());
//attaching metadata to our request object
RequestBody requestBodyMetaData = RequestBody.create(MediaType.parse("application/json"), metaDataFile);
//passing both meta data and file content for uploading
RequestBody requestBodyMultipart = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("metadata", null, requestBodyMetaData)
.addFormDataPart("file", null, RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", String.format("Bearer %s", step.getAccess_token()))
.post(requestBodyMultipart)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
try {
// Get response after rest call.
Response response = okHttpClient.newCall(request).execute();
status = response.code() == 200 ? true : false;
map.put(step.getOutput_variable(), response.code());
Asynchronously ...
public void UploadFileFromOkhttp(String filePath, String jwtToken){
String url = "https://api.baserow.io/api/user-files/upload-file/";
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
File file = new File(filePath);
builder.addFormDataPart("file" , file.getName() , RequestBody.create(MediaType.parse("image/*"), file));
RequestBody requestBody = builder.build();
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "JWT "+ jwtToken)
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new okhttp3.Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
OnError(e.getMessage());
}
});
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
final String responseData = response.body().string();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
OnSuccess(responseData);
}
});
}
});
}
First,
I've searched a lot to find a solution but were not able to find an appropriate one.
Environment
(productive) Mongoose WebServer replies to simple GET-requests (all data are transmitted via QueryString)
Apache HttpClient (single instance!) used to make hundreds of thousands single requests sequentially.
Apache HttpClient interacting with mongoose works quite well
// after each request
getMethod.releaseConnection();
...
Problem
(Mock) implementation of WebServer with Sun HttpServer works fine with FireFox / Curl
Using Apache HttpClient as with running against productive Server, performance is horrible (~ 1 request/second) on client
Using Apache HttpClient with following code found on the net results in
vast performance gain on client
resource waste due to as many open sockets in CLOSE_WAIT state as requests processed (until no more FDs ara available!)
Code:
HttpConnectionManager mgr = httpClient.getHttpConnectionManager();
if (mgr instanceof SimpleHttpConnectionManager) {
((SimpleHttpConnectionManager)mgr).shutdown();
}
Obviously I am mising something in the http server implementation, which causes this extreme "sloweness"
Any hint/help is appreciated.
Thanks in advance!
Code
HttpServer
public static void main(String[] args) throws Exception {
//System.setProperty("sun.net.httpserver.maxIdleConnections", "10");
//System.setProperty("sun.net.httpserver.idleInterval", "2000");
HttpServer server = HttpServer.create();
server.bind(new InetSocketAddress("localhost", 11111), -1);
InetSocketAddress addr = server.getAddress();
HttpContext contextSearch = server.createContext("/search.to",
new TrufflesSearchHandler());
contextSearch.getFilters().add(new ParameterFilter());
server.setExecutor(null); // creates a default executor
server.start();
}
HttpHandler
static class SearchHandler implements HttpHandler {
private JSONParser jsonParser = new JSONParser();
public void handle(HttpExchange exchange) throws IOException {
Map<String, Object> params = (Map<String, Object>) exchange
.getAttribute("parameters");
String expectedResponse = "";
int expectedHitPlace = -1;
try {
expectedResponse = (String) params.get("expectedResponse");
expectedHitPlace = Integer.parseInt((String) params
.get("expectedHitPlace"));
} catch (Exception e) {
e.printStackTrace();
}
JSONArray resultArray = null;
try {
resultArray = (JSONArray) jsonParser.parse(new String(Base64
.decodeBase64(expectedResponse)));
fillResponseWithDummyData(resultArray, expectedHitPlace);
} catch (ParseException e) {
e.printStackTrace();
}
String response = "{ \"results\": " + resultArray + "}";
Headers headers = exchange.getResponseHeaders();
headers.add("Connection", "keep-alive");
headers.add("Content-Type", "text/plain");
headers.add("Content-length", "" + response.getBytes().length);
// headers.add("Keep-Alive", "timeout=5 max=10");
exchange.sendResponseHeaders(200, 0);
// exchange.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.flush();
os.close();
// exchange.close();
}
ParameterFilter
#SuppressWarnings("restriction")
public class ParameterFilter extends Filter {
#Override
public String description() {
return "Parses the requested URI for parameters";
}
#Override
public void doFilter(HttpExchange exchange, Chain chain)
throws IOException {
parseGetParameters(exchange);
parsePostParameters(exchange);
chain.doFilter(exchange);
}
private void parseGetParameters(HttpExchange exchange)
throws UnsupportedEncodingException {
Map<String, Object> parameters = new HashMap<String, Object>();
URI requestedUri = exchange.getRequestURI();
String query = requestedUri.getRawQuery();
parseQuery(query, parameters);
exchange.setAttribute("parameters", parameters);
}
private void parsePostParameters(HttpExchange exchange)
throws IOException {
if ("post".equalsIgnoreCase(exchange.getRequestMethod())) {
#SuppressWarnings("unchecked")
Map<String, Object> parameters =
(Map<String, Object>)exchange.getAttribute("parameters");
InputStreamReader isr =
new InputStreamReader(exchange.getRequestBody(),"utf-8");
BufferedReader br = new BufferedReader(isr);
String query = br.readLine();
parseQuery(query, parameters);
}
}
private void parseQuery(String query, Map<String, Object> parameters)
throws UnsupportedEncodingException {
String encoding = System.getProperty("file.encoding");
if (query != null) {
String pairs[] = query.split("[&]");
for (String pair : pairs) {
String param[] = pair.split("[=]");
String key = null;
String value = null;
if (param.length > 0) {
key = URLDecoder.decode(param[0],
encoding);
}
if (param.length > 1) {
value = URLDecoder.decode(param[1],
encoding);
}
if (parameters.containsKey(key)) {
Object obj = parameters.get(key);
if(obj instanceof List<?>) {
List<String> values = (List<String>)obj;
values.add(value);
} else if(obj instanceof String) {
List<String> values = new ArrayList<String>();
values.add((String)obj);
values.add(value);
parameters.put(key, values);
}
} else {
parameters.put(key, value);
}
}
}
}
}
I have an application that needs to be able to post to https with an authentication request and then a register request. Currently i am able to post my authentication request to https and it works fine. When i try to post my registration request to https i keep getting the server response saying that i need to authenticate. I am authenticating before i attempt to register.
The admin of the server said that i might not be preserving the session. I am new to doing stuff with android and java. And i am new to this https stuff. I was wondering if someone could help me out here, i do not know if that is the problem for sure or even how to preserve an https session in android.
Below is my code and any suggestions are greatly appreciated!!!! Thanks in advance!!
//my helper class
public class SmartDBHelper {
private static Context tThis;
private static SmartDBHelper sDBHObject;
private static String macAddress;
private static String ipAddress;
private static HttpsURLConnection https;
/* constructor, private prevents any other class from instantiating */
private SmartDBHelper() {
}
public static synchronized SmartDBHelper getSDBHObject() {
if(sDBHObject == null) {
sDBHObject = new SmartDBHelper();
}
return sDBHObject;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public static synchronized void setSmartContext(SmartApp smartApp) {
tThis = (Context) smartApp;
}
private static synchronized void setMACIPAddress() {
WifiManager wifiMan = (WifiManager) tThis.getSystemService (tThis.WIFI_SERVICE);
WifiInfo wifiInf = wifiMan.getConnectionInfo();
macAddress = wifiInf.getMacAddress().replace(':', '-');
ipAddress = wifiMan.getDhcpInfo().toString();
int startIndex = ipAddress.indexOf(' ');
int endIndex = ipAddress.indexOf(' ', startIndex + 1);
ipAddress = ipAddress.substring(startIndex + 1, endIndex);
}
/* this function is to authenticate with the database
* it returns the id_subject, if it is greater than 0
* authentication was successful.
*/
public static synchronized int authenticate() throws MalformedURLException, ProtocolException, IOException {
Map<String, String> tempMap = new LinkedHashMap<String, String>();
tempMap.put((String) tThis.getResources().getText(R.string.postAction), (String) tThis.getResources().getText(R.string.postAuthenticate));
tempMap.put((String) tThis.getResources().getText(R.string.authUName), "username");
tempMap.put((String) tThis.getResources().getText(R.string.authPWord), "password");
String tempUrl = "https://ipaddress/health_monitoring/admin.php";
return Integer.parseInt(post(tempUrl, tempMap));
}
/* this function is to register the server to the database
* not sure of return value
*/
public static synchronized int registerServer(String nameOfServer, String description) throws MalformedURLException, ProtocolException, IOException {
setMACIPAddress();
Map<String, String> tempMap = new LinkedHashMap<String, String>();
tempMap.put((String) tThis.getResources().getText(R.string.postAction), (String) tThis.getResources().getText(R.string.postAddServer));
tempMap.put((String) tThis.getResources().getText(R.string.addServerName), "Phone");
tempMap.put((String) tThis.getResources().getText(R.string.addServerDescription), "Android");
tempMap.put((String) tThis.getResources().getText(R.string.addServerURL), "");
tempMap.put((String) tThis.getResources().getText(R.string.addServerIPAddress), ipAddress);
tempMap.put((String) tThis.getResources().getText(R.string.addServerMAC), macAddress);
String tempUrl = "https://ipaddress/health_monitoring/admin.php";
return Integer.parseInt(post(tempUrl, tempMap));
}
// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
/**
* Trust every server - dont check for any certificate
*/
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
private static String post(String urlString, Map formParameters)
throws MalformedURLException, ProtocolException, IOException {
DataOutputStream ostream = null;
trustAllHosts();
URL tempUrl;
StringBuffer buf = new StringBuffer();
if(formParameters != null) {
Set parameters = formParameters.keySet();
Iterator it = parameters.iterator();
for(int i = 0, paramCount = 0; it.hasNext(); i++) {
String parameterName = (String) it.next();
String parameterValue = (String) formParameters.get(parameterName);
if(parameterValue != null) {
parameterValue = URLEncoder.encode(parameterValue);
if(paramCount > 0) {
buf.append("&");
}
buf.append(parameterName);
buf.append("=");
buf.append(parameterValue);
++paramCount;
}
}
}
urlString = urlString + "?" + buf;
Log.v("smartdbhelper url string", urlString);
tempUrl = new URL(urlString);
https = (HttpsURLConnection) tempUrl.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
Log.v("smartdbhelper adding post parameters", https.toString());
https.setRequestMethod("POST");
https.setDoInput(true);
https.setDoOutput(true);
ostream = new DataOutputStream(https.getOutputStream());
ostream.writeBytes(buf.toString());
if( ostream != null ) {
ostream.flush();
ostream.close();
}
Object contents = https.getContent();
InputStream is = (InputStream) contents;
StringBuffer buf2 = new StringBuffer();
int c;
while((c = is.read()) != -1) {
buf2.append((char)c);
Log.v("smartdbhelper bugger", buf2.toString());
}
//https.disconnect();
return buf2.toString();
}
}
It sounds like you probably need to handle cookie headers to preserve the session. If that's the case this isn't specific to HTTPS. You'll need to find the Set-Cookie response header when you make the first request. Then every request after that you'll pass those through a Cookie request header. Here's a basic example that you can adapt for your case:
// your first request that does the authentication
URL authUrl = new URL("https://example.com/authentication");
HttpsURLConnection authCon = (HttpsURLConnection) authUrl.openConnection();
authCon.connect();
// temporary to build request cookie header
StringBuilder sb = new StringBuilder();
// find the cookies in the response header from the first request
List<String> cookies = authCon.getHeaderFields().get("Set-Cookie");
if (cookies != null) {
for (String cookie : cookies) {
if (sb.length() > 0) {
sb.append("; ");
}
// only want the first part of the cookie header that has the value
String value = cookie.split(";")[0];
sb.append(value);
}
}
// build request cookie header to send on all subsequent requests
String cookieHeader = sb.toString();
// with the cookie header your session should be preserved
URL regUrl = new URL("https://example.com/register");
HttpsURLConnection regCon = (HttpsURLConnection) regUrl.openConnection();
regCon.setRequestProperty("Cookie", cookieHeader);
regCon.connect();