Dynamic Storage (S3) access denied - swisscomdev

I'm using Amazon's Java client for S3 to access Swisscom's dynamic storage as well as S3 Ninja.
Creating buckets and putting objects works with S3 Ninja (i.e., on localhost). Creating buckets seems to work in the cloud, but putting objects doesn't:
Oct 30 12:04:44 SquaccDevLog 5751ff25-6661-43d6-92ba-91b7c0cf7c55/[App/0]: com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: null)
I may be missing something wrt https://docs.developer.swisscom.com/services/offerings/dynamic.html#authentication - but what (cf. static initializer in the code below)?
Thanks,
Paul
PS: The code below is for the most part (i.e., main and below) Amazon's S3 Java example.
/*
* The MIT License
*
* Copyright (c) 2015 Squeng AG
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package models.s3;
import java.io.*;
import java.util.*;
import play.libs.*;
import com.amazonaws.*;
import com.amazonaws.auth.*;
import com.amazonaws.services.s3.*;
import com.amazonaws.services.s3.model.*;
import com.fasterxml.jackson.databind.node.*;
/**
* Copyright © 2015 Squeng AG
*
* #author Paul
*/
public final class S3Factory
{
private S3Factory()
{
// disable instance construction
}
// FIXME: move to configuration eventually, one for development, testing, and production each
private static final AmazonS3 client;
static {
String vss = System.getenv( "VCAP_SERVICES" );
if ( vss != null ) {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setProtocol( Protocol.HTTPS );
ObjectNode VCAP_SERVICES = (ObjectNode)Json.parse( vss );
ObjectNode dynstrg = (ObjectNode)VCAP_SERVICES.get( "dynstrg" ).get( 0 );
ObjectNode credentials = (ObjectNode)dynstrg.get( "credentials" );
BasicAWSCredentials awsCreds = new BasicAWSCredentials( credentials.get( "accessKey" ).asText(), credentials.get( "sharedSecret" ).asText() );
client = new AmazonS3Client( awsCreds, clientConfig );
client.setEndpoint( credentials.get( "accessHost" ).asText() );
client.setS3ClientOptions( (new S3ClientOptions()).withPathStyleAccess( true ) );
} else {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setProtocol( Protocol.HTTP );
BasicAWSCredentials awsCreds = new BasicAWSCredentials( "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" );
client = new AmazonS3Client( awsCreds, clientConfig );
client.setEndpoint( "localhost:9444/s3" );
client.setS3ClientOptions( (new S3ClientOptions()).withPathStyleAccess( true ) );
}
}
public static AmazonS3 createBucketIfNeedBe( String bucket )
{
if ( !client.doesBucketExist( Objects.requireNonNull( bucket ) ) ) {
// FIXME: barely good enough for only one JVM
synchronized ( bucket.intern() ) {
if ( !client.doesBucketExist( bucket ) ) {
client.createBucket( bucket );
}
}
}
return client;
}
public static void main( String[] args )
throws IOException
{
String bucketName = "my-first-s3-bucket-" + UUID.randomUUID();
String key = "MyObjectKey";
System.out.println( "===========================================" );
System.out.println( "Getting Started with Amazon S3" );
System.out.println( "===========================================\n" );
try {
/*
* Create a new S3 bucket - Amazon S3 bucket names are globally unique, so once a bucket name has been taken by any user, you can't create another bucket with that same name.
*
* You can optionally specify a location for your bucket if you want to keep your data closer to your applications or users.
*/
System.out.println( "Creating bucket " + bucketName + "\n" );
client.createBucket( bucketName );
/*
* List the buckets in your account
*/
// System.out.println( "Listing buckets" );
// for ( Bucket bucket : client.listBuckets() ) {
// System.out.println( " - " + bucket.getName() );
// }
// System.out.println();
/*
* Upload an object to your bucket - You can easily upload a file to S3, or upload directly an InputStream if you know the length of the data in the stream. You can also specify your own metadata when uploading to S3, which allows you set a
* variety of options like content-type and content-encoding, plus additional metadata specific to your applications.
*/
System.out.println( "Uploading a new object to S3 from a file\n" );
client.putObject( new PutObjectRequest( bucketName, key, createSampleFile() ) );
/*
* Download an object - When you download an object, you get all of the object's metadata and a stream from which to read the contents. It's important to read the contents of the stream as quickly as possibly since the data is streamed directly
* from Amazon S3 and your network connection will remain open until you read all the data or close the input stream.
*
* GetObjectRequest also supports several other options, including conditional downloading of objects based on modification times, ETags, and selectively downloading a range of an object.
*/
System.out.println( "Downloading an object" );
S3Object object = client.getObject( new GetObjectRequest( bucketName, key ) );
System.out.println( "Content-Type: " + object.getObjectMetadata().getContentType() );
displayTextInputStream( object.getObjectContent() );
/*
* List objects in your bucket by prefix - There are many options for listing the objects in your bucket. Keep in mind that buckets with many objects might truncate their results when listing their objects, so be sure to check if the returned
* object listing is truncated, and use the AmazonS3.listNextBatchOfObjects(...) operation to retrieve additional results.
*/
// System.out.println( "Listing objects" );
// ObjectListing objectListing = client.listObjects( new ListObjectsRequest().withBucketName( bucketName ).withPrefix( "My" ) );
// for ( S3ObjectSummary objectSummary : objectListing.getObjectSummaries() ) {
// System.out.println( " - " + objectSummary.getKey() + " " + "(size = " + objectSummary.getSize() + ")" );
// }
// System.out.println();
try ( Scanner s = new Scanner( System.in ) ) {
System.out.println( "Unter data/s3 sollten das Bucket und das Object nun ersichtlich sein." );
System.out.println( "Nach dem Drücken der Enter/Return-Taste werden sie wieder gelöscht ..." );
s.nextLine();
}
/*
* Delete an object - Unless versioning has been turned on for your bucket, there is no way to undelete an object, so use caution when deleting objects.
*/
System.out.println( "Deleting an object\n" );
client.deleteObject( bucketName, key );
/*
* Delete a bucket - A bucket must be completely empty before it can be deleted, so remember to delete any objects from your buckets before you try to delete them.
*/
System.out.println( "Deleting bucket " + bucketName + "\n" );
client.deleteBucket( bucketName );
} catch ( AmazonServiceException ase ) {
System.out.println( "Caught an AmazonServiceException, which means your request made it " + "to Amazon S3, but was rejected with an error response for some reason." );
System.out.println( "Error Message: " + ase.getMessage() );
System.out.println( "HTTP Status Code: " + ase.getStatusCode() );
System.out.println( "AWS Error Code: " + ase.getErrorCode() );
System.out.println( "Error Type: " + ase.getErrorType() );
System.out.println( "Request ID: " + ase.getRequestId() );
ase.printStackTrace( System.out );
} catch ( AmazonClientException ace ) {
System.out.println( "Caught an AmazonClientException, which means the client encountered " + "a serious internal problem while trying to communicate with S3, " + "such as not being able to access the network." );
System.out.println( "Error Message: " + ace.getMessage() );
ace.printStackTrace( System.out );
}
}
/**
* Creates a temporary file with text data to demonstrate uploading a file to Amazon S3
*
* #return A newly created temporary file with text data.
*
* #throws IOException
*/
private static File createSampleFile()
throws IOException
{
File file = File.createTempFile( "aws-java-sdk-", ".txt" );
file.deleteOnExit();
Writer writer = new OutputStreamWriter( new FileOutputStream( file ) );
writer.write( "abcdefghijklmnopqrstuvwxyz\n" );
writer.write( "01234567890112345678901234\n" );
writer.write( "!##$%^&*()-=[]{};':',.<>/?\n" );
writer.write( "01234567890112345678901234\n" );
writer.write( "abcdefghijklmnopqrstuvwxyz\n" );
writer.close();
return file;
}
/**
* Displays the contents of the specified input stream as text.
*
* #param input
* The input stream to display as text.
*
* #throws IOException
*/
private static void displayTextInputStream( InputStream input )
throws IOException
{
BufferedReader reader = new BufferedReader( new InputStreamReader( input ) );
while ( true ) {
String line = reader.readLine();
if ( line == null )
break;
System.out.println( " " + line );
}
System.out.println();
}
}

Did you check to put the "PathStyleAccess" for accessing the Swisscom Object Storage ?
Most of the compatible S3 interfaces need this flag on:
This seems to work on my side; here some snippets:
S3ClientOptions options = new S3ClientOptions();
options.setPathStyleAccess(true);
AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(uid, secret));
client.setEndpoint("https://ds31s3.swisscom.com");
client.setS3ClientOptions(options);
/*
* Creating a new bucket in the
*/
String newBucket = "mybucket";
client.createBucket(newBucket, "Standard");
/*
* Add a new object
*/
client.putObject(newBucket, "CloudFoundry1.png", objectFile);
client.putObject(newBucket, "CloudFoundry2.png", objectFile);
/*
* List existing objects
*/
ObjectListing objects = client.listObjects("mybucket");
for (S3ObjectSummary summary : objects.getObjectSummaries()) {
System.out.println(summary.getKey()+ " "+summary.getOwner());
}
Hope this helps;
Best
Marco

Related

Paypal-IPN Simulator ends up in HTTP 404 error after successfully completion of the function

have spent lot of hours trying to figure this out with Paypal Simulator, Sandbox but the result is same. My handler function(handleIpn) gets called and processed, with "Verified" "Complete" status but the IPN history as well as the simulator ends up in the HTTP 404 error. On IPN Simulator page the error is - "We're sorry, but there's an HTTP error. Please try again." My set up is Java-Spring MVC.
#RequestMapping(value = "/ipnHandler.html")
public void handleIpn (HttpServletRequest request) throws IpnException {
logger.info("inside ipn");
IpnInfo ipnInfo = new IpnInfo();
Enumeration reqParamNames = request.getParameterNames();
StringBuilder cmd1 = new StringBuilder();
String pName;
String pValue;
cmd1.append("cmd=_notify-validate");
while (reqParamNames.hasMoreElements()) {
pName = (String) reqParamNames.nextElement();
pValue = request.getParameter(pName);
try{
cmd1.append("&").append(pName).append("=").append(pValue);
}
catch(Exception e){
e.printStackTrace();
}
}
try
{
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
HttpsURLConnection con = (HttpsURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "www.sandbox.paypal.com/cgi-bin/webscr");
con.setRequestProperty("Content-length", String.valueOf(cmd1.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(cmd1.toString());
output.flush();
output.close();
//4. Read response from Paypal
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String res = in.readLine();
in.close();
//5. Capture Paypal IPN information
ipnInfo.setLogTime(System.currentTimeMillis());
ipnInfo.setItemName(request.getParameter("item_name"));
ipnInfo.setItemNumber(request.getParameter("item_number"));
ipnInfo.setPaymentStatus(request.getParameter("payment_status"));
ipnInfo.setPaymentAmount(request.getParameter("mc_gross"));
ipnInfo.setPaymentCurrency(request.getParameter("mc_currency"));
ipnInfo.setTxnId(request.getParameter("txn_id"));
ipnInfo.setReceiverEmail(request.getParameter("receiver_email"));
ipnInfo.setPayerEmail(request.getParameter("payer_email"));
ipnInfo.setResponse(res);
// ipnInfo.setRequestParams(reqParamNames);
//6. Validate captured Paypal IPN Information
if (res.equals("VERIFIED")) {
//6.1. Check that paymentStatus=Completed
if(ipnInfo.getPaymentStatus() == null || !ipnInfo.getPaymentStatus().equalsIgnoreCase("COMPLETED"))
ipnInfo.setError("payment_status IS NOT COMPLETED {" + ipnInfo.getPaymentStatus() + "}");
//6.2. Check that txnId has not been previously processed
IpnInfo oldIpnInfo = this.getIpnInfoService().getIpnInfo(ipnInfo.getTxnId());
if(oldIpnInfo != null)
ipnInfo.setError("txn_id is already processed {old ipn_info " + oldIpnInfo);
//6.3. Check that receiverEmail matches with configured {#link IpnConfig#receiverEmail}
if(!ipnInfo.getReceiverEmail().equalsIgnoreCase(this.getIpnConfig().getReceiverEmail()))
ipnInfo.setError("receiver_email " + ipnInfo.getReceiverEmail()
+ " does not match with configured ipn email " + this.getIpnConfig().getReceiverEmail());
//6.4. Check that paymentAmount matches with configured {#link IpnConfig#paymentAmount}
if(Double.parseDouble(ipnInfo.getPaymentAmount()) != Double.parseDouble(this.getIpnConfig().getPaymentAmount()))
ipnInfo.setError("payment amount mc_gross " + ipnInfo.getPaymentAmount()
+ " does not match with configured ipn amount " + this.getIpnConfig().getPaymentAmount());
//6.5. Check that paymentCurrency matches with configured {#link IpnConfig#paymentCurrency}
if(!ipnInfo.getPaymentCurrency().equalsIgnoreCase(this.getIpnConfig().getPaymentCurrency()))
ipnInfo.setError("payment currency mc_currency " + ipnInfo.getPaymentCurrency()
+ " does not match with configured ipn currency " + this.getIpnConfig().getPaymentCurrency());
}
else
ipnInfo.setError("Inavlid response {" + res + "} expecting {VERIFIED}");
logger.info("ipnInfo = " + ipnInfo);
this.getIpnInfoService().log(ipnInfo);
//7. In case of any failed validation checks, throw {#link IpnException}
if(ipnInfo.getError() != null)
throw new IpnException(ipnInfo.getError());
}
catch(Exception e)
{
if(e instanceof IpnException)
throw (IpnException) e;
logger.log(Level.FATAL, e.toString(), e);
throw new IpnException(e.toString());
}
//8. If all is well, return {#link IpnInfo} to the caller for further business logic execution
paymentController.processSuccessfulPayment(ipnInfo);
}
Any help /pointers would greatly appreciate.
thanks.
Finally, got it working! Didn't realize that my issue of redirection in Spring MVC could have impact on Paypal - IPN status. May be my lack of good understanding of HTTP redirections! In above method instead of void return am now returning a jsp page, so "void" is changed to "String" with returning value the jsp file name.
Hope it does help someone!

XMPP asmack: Contact presence not working for transitions to "available"

I am using asmack 8-0.8.3.
I don't receive messages for changes of Presence from my contacts when they move to "available".
If one contact passes from "available" to "dnd", I do receive a message. But not in the other way around.
Contact passes: "available" --> "dnd" --> "available" --> "dnd"
I receive: Presence{dnd} Presence{dnd}
Whereas I expect to receive a Presence update {available} between the 2 dnd.
Since I receive presence updates except for "available" I suppose my listener works fine. Also I suppose I correctly subscribed to my contacts' presence...
private class FriendListener implements RosterListener {
public void entriesAdded(Collection<String> addresses) { }
public void entriesUpdated(Collection<String> addresses) { }
public void entriesDeleted(Collection<String> addresses) { }
public void presenceChanged(Presence presence) {
String fromUserID = StringUtils.parseBareAddress(presence.getFrom());
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString() +
" Type=" + presence.getType().toString() +
" Mode=" + presence.getMode().toString()
);
mainCallback_.updatePresenceFriend(fromUserID, presence);
}
}
public void subscribe(String friendID, String friendName) {
Presence presence = new Presence(Presence.Type.subscribe);
connection.sendPacket(presence);
RosterPacket rosterPacket = new RosterPacket();
rosterPacket.setType(IQ.Type.SET);
Item item = new Item(friendID, friendName);
item.setItemType(RosterPacket.ItemType.both);
rosterPacket.addRosterItem(item);
connection.sendPacket(rosterPacket);
System.out.println("Send subscribe to " + friendID);
subscribedUsers.add(friendID);
}
I found the problem!
Actually there was a bug in the log of my Listener, this line:
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString() +
" Type=" + presence.getType().toString() +
" Mode=" + presence.getMode().toString()
);
It made crashed when Presence.getMode()==null, so that I did not process the Presence message. But no coredump was showing in the logs, I guess because the listener is in another thread...
Changing the log by the following line solved the problem
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString()
);

SIGPIPE (Broken pipe) on tcp_disconnect to exec a client (WCF Soap 1.1 and server)

I am developing a Qt client (C++) with gSOAP lib, which is supposed to discuss with a Web Service by Microsoft (WCF). I use SOAP 1.1 on both sides.
My client code is as follows :
CustomBinding_USCOREISynchronisation service;
soap_ssl_init(); /* init OpenSSL (just once) */
soap_init2(service.soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE);
service.soap->max_keep_alive = 1000; // at most 100 calls per keep-alive session
service.soap->accept_timeout = 6000; // optional: let server time out after ten minutes of inactivity
if (soap_ssl_client_context(service.soap,
SOAP_SSL_NO_AUTHENTICATION,
NULL, /* keyfile: required only when client must authenticate to server (see SSL docs on how to obtain this file) */
NULL, /* password to read the key file (not used with GNUTLS) */
NULL, /* cacert file to store trusted certificates (needed to verify server) */ NULL, /* capath to directory with trusted certificates */
NULL /* if randfile!=NULL: use a file with random data to seed randomness */
))
{
soap_print_fault(service.soap, stderr);
exit(1);
}
_ns1__Connect req;
_ns1__ConnectResponse resp;
std::string strLogin = "tata#gmail.com";
std::string strPassword = "681982981298192891287B0A";
bool bInternalUser = true;
req.login = &strLogin;
req.password = &strPassword;
req.isInternalUser = &bInternalUser;
int err = service.__ns1__Connect(&req, &resp);
if (SOAP_OK == err)
qDebug() << ":D";
else
{
qDebug() << "Error : " << err;
soap_print_fault(service.soap, stderr);
}
qDebug() << "Result of Connect : " << resp.ConnectResult;
Problem: when I execute the program, I get a SIGPIPE (Broken pipe) in the "tcp_disconnect" function, on the exactly line "r = SSL_shutdown (soap-> ssl);".
Error message generated:
Error -1 fault: SOAP-ENV: Client [no subcode]
"End of file or no input: Operation interrupted or timed out"
Detail: [no detail]
Do you have any idea why? If you need more resources or information, please let me know!
A big thank in advance,
Louep.

How to create a SalesForce 'User' with SOAP Partner API?

I want to create a User in SalesForce programmatically by using SOAP API Partner WSDL. This is my code:
import com.sforce.soap.partner.Connector;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.soap.partner.QueryResult;
import com.sforce.soap.partner.SaveResult;
import com.sforce.soap.partner.sobject.SObject;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
import com.sforce.soap.partner.sobject.*;
import com.sforce.soap.partner.*;
import com.sforce.soap.*;
import com.sforce.*;
public class PartnerAPICreateUser {
/**
* #param args
*/
public static void main(String[] args) {
ConnectorConfig config = new ConnectorConfig();
config.setUsername("waprau#waprau.com");
config.setPassword("dhskjhkjgfkjsdhkfjg");
PartnerConnection connection = null;
try {
SObject user = new SObject();
user.setType("user");
user.setField("Alias", "abcd");
user.setField("DefaultGroupNotificationFrequency", "P");
user.setField("DigestFrequency", "D");
user.setField("Email", "abcd#pqrs.com");
user.setField("EmailEncodingKey", "ISO-8859-1");
user.setField("LanguageLocaleKey", "English");
user.setField("LastName", "Rau");
user.setField("LocaleSidKey", "En");
user.setField("TimeZoneSidKey", "America/Los_Angeles");
user.setField("Username", "abcd#pqrs.com");
user.setField("UserPermissionsCallCenterAutoLogin", "true");
user.setField("UserPermissionsMarketingUser", "true");
user.setField("UserPermissionsOfflineUser", "true");
connection = Connector.newConnection(config);
SaveResult[] results = connection.create(new SObject[] { user });
System.out.println("Created user: " + results[0].getId());
QueryResult queryResults = connection
.query("SELECT Id, Name from User "
+ "ORDER BY CreatedDate DESC LIMIT 5");
if (queryResults.getSize() > 0) {
for (SObject s : queryResults.getRecords()) {
System.out.println("Id: " + s.getField("Id") + " - Name: "
+ s.getField("Name"));
}
}
} catch (ConnectionException ce) {
ce.printStackTrace();
}
}
}
However, when I execute this Java program it gives following output which shows 'Created user: null' :-(
Created user: null
Id: 005E0000001fb3vIAA - Name: Rau
Id: 005E0000001fVTTIA2 - Name: Chatter Expert
Id: 005E0000001fVU1IAM - Name: Wap Rau
Administrative Permissions when I go to MyName > Setup > Manage Users (in Administration Setup) > Profiles
Can you tell me whats wrong?
Thanks,
Wap Rau
The create call is returning an error, but you don't check for it, the returned SaveResult will tell you why it didn't create the user, you want something like
SaveResult[] results = connection.create(new SObject[] { user });
if (results[0].isSuccess())
System.out.println("Created user: " + results[0].getId());
else
System.out.println("Error: " + results[0].getErrors()[0].getStatusCode() +
":" + results[0].getErrors()[0].getMessage());

Binary File Download using socket connection in Java ME

I am trying to download a pdf file on my mobile (using Java ME) using SocketConnection Api. The idea is to send the server a HTTP GET request, and it replies back with the data for pdf file. However, the problem I am facing is that the server initially replies back with string data (the HTTP Headers), and then the binary data. I just want to store the binary data (the pdf file).
I have written this code so far, and it works perfectly fine as far as the server replies back with string data. However, when it replies back with binary data, this code still tries to store everything as string, correctly storing the initially returned HTTP Headers (not required) and then garbled bits corresponding to the binary data of my PDF file.
public void FileDownload() {
try {
sc = (SocketConnection) Connector.open("socket://" + hostname + ":" + port);
OutputStream os = sc.openOutputStream();
os.write(("GET " + link_to_file_to_be_downloaded + " HTTP/1.0\r\n").getBytes("UTF-8"));
os.write(("HOST: " + hostname + "\r\n").getBytes("UTF-8"));
os.write(("\r\n").getBytes("UTF-8"));
os.flush();
os.close();
String url = "file:///E:/Data/" + "binary_data.pdf";
FileConnection fconn = (FileConnection) Connector.open(url, Connector.READ_WRITE);
if (!fconn.exists()) {
fconn.create();
}
OutputStream ops = fconn.openOutputStream();
byte data = 0;
in = sc.openInputStream();
data = (byte) in.read();
while (data != -1) {
ops.write(data);
data = (byte) in.read();
}
ops.flush();
ops.close();
fconn.close();
} catch (IOException ex) {
parent_class.main_form.append("Exception occured while "
+ "downloading file: " + ex.toString() + "\n");
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
parent_class.main_form.append("Exception occured while "
+ "downloading file: " + ex.toString() + "\n");
}
}
}
}
This is what gets stored in the file "binary_data.pdf" using this code -
HTTP/1.1 200 OK
Date: Sun, 25 Mar 2012 07:03:10 GMT
Server: Apache/2.2.14 (Ubuntu)
Last-Modified: Tue, 20 Mar 2012 22:00:45 GMT
ETag: "420050-12bad-4bbb3ce85fd21"
Accept-Ranges: bytes
Content-Length: 76717
Content-Type: application/pdf
Via: 1.0 www.XXX.XXX.org
Connection: close
%PDF-1.4
%????
3 0 obj <<
/Length 4077
/Filter /FlateDecode
>>
stream
x??ZYs?6~????9U.?#??Udg?M*qYJ???T-4?fq? #Z????<FT?}
lt7??n???_???4?s???????"
3????<???^?V?z??M?z??m?^????V???o??S'm6?????.??/Sx??Y?av?MB?*b^?f??/?IO??B??q??/?(??aT?a?##??,?%???Z8? ?]??-?\?]??????nw?2?;?????Z?;?[}??????&J=ml??-??V?|??:??"?(?Gf??D??~?QW?U?Z???cP?b???QX
(This operation might be simpler using the high level HttpConnection api, but I wish to understand how everything works at the most basic level, and hence I am using the SocketConnection api instead.)
In short, what I wish my app to do is simply interpret the data replied by the server correctly, either as string or binary, and then accordingly store the binary file (possibly discarding the string HTTP headers).
I found the solution. Below is the working code.
I am first storing the header response as a string. Headers are terminated by \r\n\r\n, (so, read in bytes upto these characters). Later am storing the (possibly) binary data in a file separately.
public String FileDownloadNonPersistently() {
String server_reply = new String();
try {
sc = (SocketConnection) Connector.open("socket://" + hostname + ":" + port);
os = sc.openOutputStream();
os.write(("GET " + link_to_file_to_be_downloaded +
" HTTP/1.0\r\n").getBytes("UTF-8"));
os.write(("HOST: " + hostname + "\r\n").getBytes("UTF-8"));
os.write(("\r\n").getBytes("UTF-8"));
os.flush();
os.close();
in = sc.openInputStream();
// 1. Read the response header from server separately beforehand.
byte data;
String temp_char = "";
while (!"\r\n\r\n".equals(temp_char)) {
data = (byte) in.read();
server_reply += String.valueOf((char) data);
if (((char) data) == '\r' || ((char) data) == '\n') {
temp_char += String.valueOf((char) data);
} else {
temp_char = "";
}
}
// 2. Recieving the actual data, be it text or binary
current = 0;
mybytearray = new byte[filesize];
bytesRead = in.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead = in.read(mybytearray, current,
(mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
// Store recieved data to file, if set true from options
if (tcp_save_downloaded_file == true) {
// decide an appropriate file name acc. to download link
String url = "file:///E:/Data/" + "tcp_downloaded_file.pdf";
FileConnection fconn = (FileConnection)
Connector.open(url, Connector.READ_WRITE);
if (!fconn.exists()) { // XXX. what if file already present? overwrite or append mode?
fconn.create();
}
OutputStream ops = fconn.openOutputStream();
ops.write(mybytearray, 0 , current);
ops.flush();
ops.close();
}
} catch (Exception ex) {
parent_class.main_form.append("Exception occured while "
+ "downloading file: " + ex.toString() + "\n\n");
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
parent_class.main_form.append("Exception occured while "
+ "closing inputstream "
+ "after downloading file: " + ex.toString() + "\n\n");
}
}
// XXX. see if you need to close the OutputStreams and
// SocketConnection as well.
return server_reply;
}
}
The first 10 lines are the HTTP message headers. For more information on them please go to https://www.rfc-editor.org/rfc/rfc2616#page-31.
The blank line identifies where the body starts.
You can start saving the pdf content from line 12 onwards, but you should do it using a different read method.
Instead of
data = (byte) in.read();
while (data != -1) {
ops.write(data);
data = (byte) in.read();
}
please try
byte buff[] = new byte[1024];
int len = in.read(buff);
while (len > 0) {
ops.write(buff, 0, len);
len = in.read(buff);
}