use of org.odk.collect.android.openrosa.CaseInsensitiveHeaders in project collect by opendatakit.
the class InstanceServerUploader method uploadOneSubmission.
/**
* Uploads all files associated with an instance to the specified URL. Writes fail/success
* status to database.
* <p>
* Returns a custom success message if one is provided by the server.
*/
@Override
public String uploadOneSubmission(Instance instance, String urlString) throws UploadException {
Uri submissionUri = Uri.parse(urlString);
long contentLength = 10000000L;
// the proper scheme.
if (uriRemap.containsKey(submissionUri)) {
submissionUri = uriRemap.get(submissionUri);
Timber.i("Using Uri remap for submission %s. Now: %s", instance.getDbId(), submissionUri.toString());
} else {
if (submissionUri.getHost() == null) {
submissionComplete(instance, false);
throw new UploadException(FAIL + "Host name may not be null");
}
URI uri;
try {
uri = URI.create(submissionUri.toString());
} catch (IllegalArgumentException e) {
submissionComplete(instance, false);
Timber.d(e.getMessage() != null ? e.getMessage() : e.toString());
throw new UploadException(getLocalizedString(Collect.getInstance(), R.string.url_error));
}
HttpHeadResult headResult;
CaseInsensitiveHeaders responseHeaders;
try {
headResult = httpInterface.executeHeadRequest(uri, webCredentialsUtils.getCredentials(uri));
responseHeaders = headResult.getHeaders();
if (responseHeaders.containsHeader(OpenRosaConstants.ACCEPT_CONTENT_LENGTH_HEADER)) {
String contentLengthString = responseHeaders.getAnyValue(OpenRosaConstants.ACCEPT_CONTENT_LENGTH_HEADER);
try {
contentLength = Long.parseLong(contentLengthString);
} catch (Exception e) {
Timber.e(e, "Exception thrown parsing contentLength %s", contentLengthString);
}
}
} catch (Exception e) {
submissionComplete(instance, false);
throw new UploadException(FAIL + (e.getMessage() != null ? e.getMessage() : e.toString()));
}
if (headResult.getStatusCode() == HttpsURLConnection.HTTP_UNAUTHORIZED) {
submissionComplete(instance, false);
throw new UploadAuthRequestedException(getLocalizedString(Collect.getInstance(), R.string.server_auth_credentials, submissionUri.getHost()), submissionUri);
} else if (headResult.getStatusCode() == HttpsURLConnection.HTTP_NO_CONTENT) {
// Redirect header received
if (responseHeaders.containsHeader("Location")) {
try {
Uri newURI = Uri.parse(URLDecoder.decode(responseHeaders.getAnyValue("Location"), "utf-8"));
// Allow redirects within same host. This could be redirecting to HTTPS.
if (submissionUri.getHost().equalsIgnoreCase(newURI.getHost())) {
// Re-add params if server didn't respond with params
if (newURI.getQuery() == null) {
newURI = newURI.buildUpon().encodedQuery(submissionUri.getEncodedQuery()).build();
}
uriRemap.put(submissionUri, newURI);
submissionUri = newURI;
} else {
// Don't follow a redirection attempt to a different host.
// We can't tell if this is a spoof or not.
submissionComplete(instance, false);
throw new UploadException(FAIL + "Unexpected redirection attempt to a different host: " + newURI.toString());
}
} catch (Exception e) {
submissionComplete(instance, false);
throw new UploadException(FAIL + urlString + " " + e.toString());
}
}
} else {
if (headResult.getStatusCode() >= HttpsURLConnection.HTTP_OK && headResult.getStatusCode() < HttpsURLConnection.HTTP_MULT_CHOICE) {
submissionComplete(instance, false);
throw new UploadException("Failed to send to " + uri + ". Is this an OpenRosa " + "submission endpoint? If you have a web proxy you may need to log in to " + "your network.\n\nHEAD request result status code: " + headResult.getStatusCode());
}
}
}
// When encrypting submissions, there is a failure window that may mark the submission as
// complete but leave the file-to-be-uploaded with the name "submission.xml" and the plaintext
// submission files on disk. In this case, upload the submission.xml and all the files in
// the directory. This means the plaintext files and the encrypted files will be sent to the
// server and the server will have to figure out what to do with them.
File instanceFile = new File(instance.getInstanceFilePath());
File submissionFile = new File(instanceFile.getParentFile(), "submission.xml");
if (submissionFile.exists()) {
Timber.w("submission.xml will be uploaded instead of %s", instanceFile.getAbsolutePath());
} else {
submissionFile = instanceFile;
}
if (!instanceFile.exists() && !submissionFile.exists()) {
submissionComplete(instance, false);
throw new UploadException(FAIL + "instance XML file does not exist!");
}
List<File> files = getFilesInParentDirectory(instanceFile, submissionFile);
// TODO: when can this happen? It used to cause the whole submission attempt to fail. Should it?
if (files == null) {
throw new UploadException("Error reading files to upload");
}
HttpPostResult postResult;
ResponseMessageParser messageParser = new ResponseMessageParser();
try {
URI uri = URI.create(submissionUri.toString());
postResult = httpInterface.uploadSubmissionAndFiles(submissionFile, files, uri, webCredentialsUtils.getCredentials(uri), contentLength);
int responseCode = postResult.getResponseCode();
messageParser.setMessageResponse(postResult.getHttpResponse());
if (responseCode != HttpsURLConnection.HTTP_CREATED && responseCode != HttpsURLConnection.HTTP_ACCEPTED) {
UploadException exception;
if (responseCode == HttpsURLConnection.HTTP_OK) {
exception = new UploadException(FAIL + "Network login failure? Again?");
} else if (responseCode == HttpsURLConnection.HTTP_UNAUTHORIZED) {
exception = new UploadException(FAIL + postResult.getReasonPhrase() + " (" + responseCode + ") at " + urlString);
} else {
if (messageParser.isValid()) {
exception = new UploadException(FAIL + messageParser.getMessageResponse());
} else if (responseCode == HttpsURLConnection.HTTP_BAD_REQUEST) {
Timber.w(FAIL + postResult.getReasonPhrase() + " (" + responseCode + ") at " + urlString);
exception = new UploadException("Failed to upload. Please make sure the form is configured to accept submissions on the server");
} else {
exception = new UploadException(FAIL + postResult.getReasonPhrase() + " (" + responseCode + ") at " + urlString);
}
}
submissionComplete(instance, false);
throw exception;
}
} catch (Exception e) {
submissionComplete(instance, false);
throw new UploadException(FAIL + "Generic Exception: " + (e.getMessage() != null ? e.getMessage() : e.toString()));
}
submissionComplete(instance, true);
if (messageParser.isValid()) {
return messageParser.getMessageResponse();
}
return null;
}
use of org.odk.collect.android.openrosa.CaseInsensitiveHeaders in project collect by opendatakit.
the class OkHttpConnection method executeHeadRequest.
@NonNull
@Override
public HttpHeadResult executeHeadRequest(@NonNull URI uri, @Nullable HttpCredentialsInterface credentials) throws Exception {
OpenRosaServerClient httpClient = clientFactory.get(uri.getScheme(), userAgent, credentials);
Request request = new Request.Builder().url(uri.toURL()).head().build();
Timber.i("Issuing HEAD request to: %s", uri.toString());
Response response = httpClient.makeRequest(request, new Date());
int statusCode = response.code();
CaseInsensitiveHeaders responseHeaders = new CaseInsensitiveEmptyHeaders();
if (statusCode == HttpURLConnection.HTTP_NO_CONTENT) {
responseHeaders = new OkHttpCaseInsensitiveHeaders(response.headers());
}
discardEntityBytes(response);
return new HttpHeadResult(statusCode, responseHeaders);
}
Aggregations