use of org.odk.collect.android.openrosa.HttpPostResult 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.HttpPostResult in project collect by opendatakit.
the class OkHttpConnection method executePostRequest.
@NonNull
private HttpPostResult executePostRequest(@NonNull URI uri, @Nullable HttpCredentialsInterface credentials, MultipartBody multipartBody) throws Exception {
OpenRosaServerClient httpClient = clientFactory.get(uri.getScheme(), userAgent, credentials);
HttpPostResult postResult;
Request request = new Request.Builder().url(uri.toURL()).post(multipartBody).build();
Response response = httpClient.makeRequest(request, new Date());
if (response.code() == 204) {
throw new Exception();
}
postResult = new HttpPostResult(response.body().string(), response.code(), response.message());
discardEntityBytes(response);
return postResult;
}
use of org.odk.collect.android.openrosa.HttpPostResult in project collect by opendatakit.
the class OkHttpConnection method uploadSubmissionAndFiles.
@NonNull
@Override
public HttpPostResult uploadSubmissionAndFiles(@NonNull File submissionFile, @NonNull List<File> fileList, @NonNull URI uri, @Nullable HttpCredentialsInterface credentials, @NonNull long contentLength) throws Exception {
HttpPostResult postResult = null;
boolean first = true;
int fileIndex = 0;
int lastFileIndex;
while (fileIndex < fileList.size() || first) {
lastFileIndex = fileIndex;
first = false;
long byteCount = 0L;
RequestBody requestBody = RequestBody.create(MediaType.parse(HTTP_CONTENT_TYPE_TEXT_XML), submissionFile);
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM).addPart(MultipartBody.Part.createFormData("xml_submission_file", submissionFile.getName(), requestBody));
Timber.i("added xml_submission_file: %s", submissionFile.getName());
byteCount += submissionFile.length();
for (; fileIndex < fileList.size(); fileIndex++) {
File file = fileList.get(fileIndex);
String contentType = fileToContentTypeMapper.map(file.getName());
RequestBody fileRequestBody = RequestBody.create(MediaType.parse(contentType), file);
multipartBuilder.addPart(MultipartBody.Part.createFormData(file.getName(), file.getName(), fileRequestBody));
byteCount += file.length();
Timber.i("added file of type '%s' %s", contentType, file.getName());
// we've added at least one attachment to the request...
if (fileIndex + 1 < fileList.size()) {
if ((fileIndex - lastFileIndex + 1 > 100) || (byteCount + fileList.get(fileIndex + 1).length() > contentLength)) {
// the next file would exceed the 10MB threshold...
Timber.i("Extremely long post is being split into multiple posts");
multipartBuilder.addPart(MultipartBody.Part.createFormData("*isIncomplete*", "yes"));
// advance over the last attachment added...
++fileIndex;
break;
}
}
}
MultipartBody multipartBody = multipartBuilder.build();
postResult = executePostRequest(uri, credentials, multipartBody);
if (postResult.getResponseCode() != HttpURLConnection.HTTP_CREATED && postResult.getResponseCode() != HttpURLConnection.HTTP_ACCEPTED) {
return postResult;
}
}
return postResult;
}
Aggregations