Logging the XML or JSON sent by RestSharp - restsharp

I'm using RestSharp to send information to a API. I would like to log the XML that I've sent to this API so I can debug later.
I would like to do something like this:
var request = new RestRequest(resourcePath, method);
request.AddBody(dto);
Logger.Log(request.Content);
var response = Client.Execute(request);
But, the actual request sent by RestSharp does not seem to be exposed.

Everything sent in the request is available in request.Parameters.
To make getting the request body easier I created this extension method:
public static class RestSharpExtensions
{
public static string GetBody(this IRestRequest request)
{
var bodyParameter = request.Parameters
.FirstOrDefault(p => p.Type == ParameterType.RequestBody);
return bodyParameter == null
? null
: bodyParameter.Value.ToString();
}
}

Related

RestRequest Body not received in .net core web api

I am trying to build a service client to simplify calling my microservices in .net core.
Here is a service client sample:
public ProductServiceClient(SystemEnvironment.MachineEnvironment? environment = null)
{
this.url = ServiceEnvironment.Urls.GetUrl(ServiceEnvironment.Service.Product, environment);
}
private RestClient GetClient(string method)
{
return new RestClient(url + "/api/" + method);
}
private RestRequest GetRestRequest(Method method)
{
var restRequest = new RestRequest(method);
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddHeader("Content-Type", "application/json");
return restRequest;
}
public FindProductsResponse FindProducts(FindProductsRequest request)
{
var restRequest = GetRestRequest(Method.GET);
restRequest.AddJsonBody(request);
var client = this.GetClient("Products");
var restResponse = client.Get(restRequest);
return new JsonDeserializer().Deserialize<FindProductsResponse>(restResponse);
}
public void Dispose()
{
}
And here is how I am trying to read it in my .net core api:
[HttpGet]
public ActionResult<FindProductsResponse> Get()
{
var request = "";
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
request = reader.ReadToEnd();
}
var buildRequest = JsonConvert.DeserializeObject<FindProductsRequest>(request);
var products = _service.FindProducts(buildRequest);
if (products != null && products.Any())
{
return new FindProductsResponse()
{
Products = products
};
}
return BadRequest("Not found");
}
However the request variable is always empty after Request.Body has been processed by the StreamReader.
If I make the same request from Postman (also using GET), I get the body just fine.
What am I doing wrong here?
EDIT: This is the unit test calling the api:
[Test]
public void Test1()
{
using (var productServiceClient = new ProductServiceClient())
{
var products = productServiceClient.FindProducts(new FindProductsRequest()
{
Id = 50
}).Products;
}
}
It can be your Request.Body has been already consumed.
Try to call Request.EnableRewind() before to open the StreamReader.
I'm not sure why you are manually doing it. It looks like you are reinventing the wheel. ASP.NET Core already does that for you.
This is what your service should look like:
[HttpGet] // oops, GET requests will not allow Bodies, this won't work
public ActionResult<FindProductsResponse> Get([FromBody]FindProductsRequest buildRequest)
{
// skip all the serialization stuff, the framework does that for you
var products = _service.FindProducts(buildRequest);
if (products != null && products.Any())
{
return new FindProductsResponse()
{
Products = products
};
}
return BadRequest("Not found");
}
And if you don't want to redo all the busy work that is retyping all the code on the client side, I suggest you read up on swagger (probably in the form of Swashbuckle). Client code can be generated. Even from within Visual Studio, if you right-click on the project and in the context menu pick "Add REST API Client...". Please don't erroneously hand-code what can be generated flawlessly by a machine instead. I don't really know what went wrong in your specific case, but searching bugs that could be avoided altogether is just busywork, that time should be spent on other parts of the program.
I just realized this is a GET request. ASP.NET will not recognize bodies for GET-Requests. You will need to make it a PUT or POST request or put your parameters in the query string.
If you happen to make that mistake as often as I did, you might want to write some unit tests that cover this. Because .NET is not helping you there. Been there, done that..

How to return multipart content with html and xml

I have to re-write a web service in .NET Core 2.2, and the service must return a multipart response with XML and base-64 encoded HTML. The current service is a really old java program with no documentation.
The request comes from an old service that can't change and must receive HTML 4.01 as the response. An actual sample is shown below.
What kind of response object do I return?
How do I combine the XML and encoded HTML together into one response object?
I don't expect anyone to write my code for me but I would appreciate some help getting started.
Sample response
--75df5969-8400-11d5-c000-0021ffffff97
Content-type: text/xml; charset="UTF-8"
Content-id: XMLROOT
<?xml version="1.0" encoding="UTF-8"?><XMLROOT><Service><StatusCd>0</StatusCd></Service></XMLROOT>
--75df5969-8400-11d5-c000-0021ffffff97
Content-type: application/html
Content-id: Inquiry.html
Content-description: Response to View Inquiry
PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEgVHJhbnNpdGlvbmFsLy9FTiI+Cgo8SFRNTD4KPEhFQUQ+CjxNRVRBIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PUlTTy04ODU5LTEiPgo8TUVUQSBodHRwLWVxdWl2PSJDb250ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KCgk8U1RZTEUgVFlQRT0idGV4dC9jc3MiPgoJCVRSIHsgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmV5IH0KCQkudGREYXRhIHsKCSAJCWZvbnQtc2l6ZTo4cHQ7CgkJCWNvbG9yOiMwMDAwOUM7CgkJCWZvbnQtZmFtaWx5OlZlcmRhbmEsIEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IH0KCQkudGRMYWJlbCB7CgkgCQlmb250LXNpemU6OHB0OwoJCQlmb250LXdlaWdodDpib2xkZXI7CgkJCWZvbnQtZmFtaWx5OlZlcmRhbmEsIEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IH0KCQkudGRIZWFkIHsKCQkJYmFja2dyb3VuZC1jb2xvcjojODA4MDgwOwoJCQl0ZXh0LWFsaWduOmNlbnRlcjsKCSAJCWZvbnQtc2l6ZTo4cHQ7CgkJCWZvbnQtd2VpZ2h0OmJvbGRlcjsKCQkJZm9udC1mYW1pbHk6VmVyZGFuYSwgQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgfQoJPC9TVFlMRT4KCjxUSVRMRT5JbnF1aXJ5PC9USVRMRT4KPC9IRUFEPgo8Qk9EWT4KPHRhYmxlIEJPUkRFUj0iMCIgQ0VMTFBBRERJTkc9IjAiIENFTExTUEFDSU5HPSIwIiBXSURUSD0iNzAwIj4KCTx0cj4gCgkJPHRkIEJHQ09MT1I9IiNmZmZmZmYiPgoJCQk8VEFCTEUgQk9SREVSPSIxIiBDRUxMUEFERElORz0iMiIgQ0VMTFNQQUNJTkc9IjEiIFdJRFRIPSI3MDAiPgoJCQkJPFRSPjxURCBDT0xTUEFOPSI0IiBBTElHTj0iY2VudGVyIiBCR0NPTE9SPSIjZmZmZmZmIj4KCQkJCQlUZXN0IG1lc3NhZ2UgCgkJCQk8L1REPjwvVFI+CgkJCTwvVEFCTEU+CQoJCTx0ZD48L3RkPgoJPHRyPjwvdHI+CjwvdGFibGU+Cgo8L0JPRFk+CjwvSFRNTD4=
--75df5969-8400-11d5-c000-0021ffffff97--
What kind of response object do I return? How do I combine the XML and encoded HTML together into one response object?
There's no such a built-in result type. However, it would be easy to create a custom MultipartResult that will contains the XML + HTML (encoded). For example:
public class XmlAndEncodedHtmlMultipartResult : IActionResult
{
private StringContent _xmlContent;
private StringContent _htmlContent;
private MultipartContent _multipartContent=new MultipartContent(Subtype); // the final content
public static string Subtype = "my-xml+html" ; // `content-type: multipart/{Subtype}`
public XmlAndEncodedHtmlMultipartResult SetXmlContent(string xml, string contentId = "XMLROOT")
{
var xmlContent = new StringContent(xml, Encoding.UTF8, "text/xml");
xmlContent.Headers.Add("Content-id", contentId);
this._xmlContent = xmlContent;
return this;
}
public XmlAndEncodedHtmlMultipartResult SetEncodedHtmlContent(string rawHtml,string contentId="Inquiry.html", string description="Response to View Inquiry")
{
var bytes= Encoding.UTF8.GetBytes(rawHtml);
var encodedHtml = Convert.ToBase64String(bytes);
var htmlContent = new StringContent(encodedHtml, Encoding.UTF8, "application/html");
htmlContent.Headers.Add("Content-id", contentId);
htmlContent.Headers.Add("Content-description",description);
this._htmlContent = htmlContent;
return this;
}
public async Task ExecuteResultAsync(ActionContext context)
{
if(this._htmlContent ==null || this._xmlContent ==null){ throw new Exception("html content & xml must be null");}
this._multipartContent.Add(this._xmlContent);
this._multipartContent.Add(this._htmlContent);
var response = context.HttpContext.Response;
response.ContentType = this._multipartContent.Headers.ContentType.ToString();
// ... custom other headers as you like
await _multipartContent.CopyToAsync(response.Body);
}
}
In your action, just invoke it as below :
public IActionResult Privacy()
{
var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XMLROOT><Service><StatusCd>0</StatusCd></Service></XMLROOT>";
var html = "<html><head></head><body>hello,world</body></html>";
return new XmlAndEncodedHtmlMultipartResult().SetEncodedHtmlContent(html).SetXmlContent(xml);
}

Xamarin Android - Can a WCF SOAP webservice use HttpClient for TLS 1.2?

I have a customer who requires TLS 1.2 for PCI compliance. Xamarin Android does not support TLS 1.2 very well. According to this
Native HttpClientHandler and this Transport Layer Security, you can either use HttpClient with their special mechanism to access the native Java support on Android 5 and higher, or you can use the ModernHttpClient.
However, WCF SOAP Webservice proxies generated with SvcUtil appear to use HttpWebRequest, and not HttpClient.
What's the recommended way to call WCF SOAP services using HttpClient (or ModernHttpClient)? Will I have to manually write my own interfaces or can I use the proxy classes and serialize/deserialize them myself? I'd rather not have to completely start from scratch, especially since it looks like TLS 1.2 is currently being added to Mono.
i have used that type of service and it is working here i have share relevant code please try it.
static void TryByWebRequest(string soapMethod)
{
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"
<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body>
<" + soapMethod + #"
xmlns=""your URI""
xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<InputXMLString>
" +
System.Security.SecurityElement.Escape(inputXML)
+ #"
</InputXMLString>
<OutputXMLString/>
</" + soapMethod + #">
</s:Body>
</s:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
static HttpWebRequest CreateWebRequest(string soapMethod)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(#"Your .asmx URL ");
webRequest.Headers.Add(#"SOAPAction", "your URI \" + soapMethod);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
I got this working. Since this is a (hopefully) temporary solution, my goal was to create drop-in replacements for the Proxy-generated classes, and I got pretty close. The key was to figure out how to use the DataContractSerializer to create a SOAP envelope to send, and deserialize the results.
I was successful with everything except for the serialization of the SOAP envelope that gets sent to the web service. I ended up manually wrapping the XML in the <envelope> and <body> tags. Nothing that I did could get the DataContractSerializer to create these correctly, although the Body contents were ok. The Deserializer was able to handle the response from the web service without any problem though. WCF services are very picky about the format of the SOAP envelope, and getting the classes annotated just right was a challenge.
For each function call, I had to create a Request object that wraps the parameters being sent to the web service, and a Response object that wraps the out parameters and the return code.
These look something like this, where the FunctionName is the name of the WCF function call that the proxys generated.
// request envelope
[System.Runtime.Serialization.DataContractAttribute(Name = "FunctionName", Namespace = "http://tempuri.org/")]
public class FunctionName_Request
{
[System.Runtime.Serialization.DataMemberAttribute()]
public NameSpaceFunctionNameObject1 CallingObject1;
[System.Runtime.Serialization.DataMemberAttribute()]
public NameSpaceFunctionNameObject2 CallingObject2;
}
// response envelope
[System.Runtime.Serialization.DataContractAttribute(Name = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class FunctionName_ResponseEnvelope
{
[System.Runtime.Serialization.DataContractAttribute(Name = "Body", Namespace = "http://tempuri.org/")]
public class FunctionName_ResponseBody
{
[System.Runtime.Serialization.DataContractAttribute(Name = "FunctionNameResponse", Namespace = "http://tempuri.org/")]
public class FunctionName_Response
{
[System.Runtime.Serialization.DataMemberAttribute()]
public FunctionNameReturnCodes Result;
[System.Runtime.Serialization.DataMemberAttribute()]
public FunctionNameResponseObject Response;
}
[System.Runtime.Serialization.DataMemberAttribute()]
public FunctionName_Response FunctionNameResponse;
}
[System.Runtime.Serialization.DataMemberAttribute()]
public FunctionName_ResponseBody Body;
}
Then, I can write a replacement function that my client code can call, which has exactly the same signature as the original Proxy-generated function.
// FunctionName
public FunctionNameReturnCodes FunctionName(out FunctionNameResponseObject Response, NameSpaceFunctionNameObject1 CallingObject1, NameSpaceFunctionNameObject2 CallingObject2)
{
// create the request envelope
FunctionName_Request req = new FunctionName_Request();
req.CallingObject1 = CallingObject1;
req.CallingObject2 = CallingObject2;
// make the call
FunctionName_ResponseEnvelope resp = MakeWCFCall<FunctionName_ResponseEnvelope>(_EndpointAddress, _ServerName, req);
// get the response object
Response = resp.Body.FunctionName_Response.Response;
// result
return resp.Body.FunctionName_Response.Result;
}
Finally, this is the function that actually serializes and deserializes the object into the HttpClient. In my case, these are synchronous, but you could easily adapt this to work in the standard async case. It's template so it works with any of the proxy-generated types.
/////////////////////////////////////////////////////////////////////
// make a WCF call using an HttpClient object
// uses the DataContractSerializer to serialze/deserialze the messages from the objects
//
// We manually add the <s:Envelope> and <s:Body> tags. There should be a way to get
// the DataContractSerializer to write these too, but everything I tried gave a message
// that was not able to be procesed by the service. This includes the Message object.
// Deserializing works fine, but serializing did not.
private T MakeWCFCall<T>(string strEndpoint, string strServerName, object SourceObject)
{
T Response = default(T);
string strSoapMessage = "";
string strSoapAction = "";
// get the Soap Action by using the DataContractAttribute's name
// start by getting the list of custom attributes.
// there should only be the one
object[] oaAttr = SourceObject.GetType().GetCustomAttributes(false);
if (oaAttr.Length > 0)
{
// iterate just in case there are more
foreach (DataContractAttribute oAttr in oaAttr)
{
// make sure we got one
if (oAttr != null)
{
// this is the action!
strSoapAction = oAttr.Name;
break;
}
}
}
// serialize the request into a string
// use a memory stream as the source
using (MemoryStream ms = new MemoryStream())
{
// create the DataContractSerializer
DataContractSerializer ser = new DataContractSerializer(SourceObject.GetType());
// serialize the object into the memory stream
ser.WriteObject(ms, SourceObject);
// seek to the beginning so we can read back out of the stream
ms.Seek(0, SeekOrigin.Begin);
// create the stream reader
using (var streamReader = new StreamReader(ms))
{
// read the message back out, adding the Envelope and Body wrapper
strSoapMessage = #"<s:Envelope xmlns:s = ""http://schemas.xmlsoap.org/soap/envelope/""><s:Body>" + streamReader.ReadToEnd() + #"</s:Body></s:Envelope>";
}
}
// now create the HttpClient connection
using (var client = new HttpClient(new NativeMessageHandler()))
{
//specify to use TLS 1.2 as default connection
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
// add the Soap Action header
client.DefaultRequestHeaders.Add("SOAPAction", "http://tempuri.org/" + strServerName + "/" + strSoapAction);
// encode the saop message
var content = new StringContent(strSoapMessage, Encoding.UTF8, "text/xml");
// post to the server
using (var response = client.PostAsync(new Uri(strEndpoint), content).Result)
{
// get the response back
var soapResponse = response.Content.ReadAsStringAsync().Result;
// create a MemoryStream to use for serialization
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(soapResponse)))
{
// create the reader
// set the quotas
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(
memoryStream,
Encoding.UTF8,
new XmlDictionaryReaderQuotas() { MaxArrayLength = 5000000, MaxBytesPerRead = 5000000, MaxStringContentLength = 5000000 },
null);
// create the Data Contract Serializer
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
// deserialize the response
Response = (T)serializer.ReadObject(reader);
}
}
}
// return the response
return Response;
}
This approach allowed me to quickly write wrappers for all of my WCF service functions, and it's working well so far.

dropbox access token for others to upload to my folder

I plan to have a server program fetching my dropbox account access token and pass to
client program to uplaod to my dropbox folder. Client does not need DB account or login and is able to send file to my DB folder (thus NOT using OAuth ...). Something similar to:
this
and this
but without user upload to server first, i.e., once user get the access token, they upload directly to DB.
I've tried to use Apache httpclient 4.3 to simulate a browser to perform getting request token, sending login-info to get acces token, but get stuck on upload the file via post to a form. Error is HTTP 400 Bad Request ...
executing request:GET https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Request Token: moiejtzdLqTA_0sh3gQyNZAI
executing request:POST https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Access Token: 5Ot52QKDbDPSsL1ApU4MIapJ
executing request:POST https://dl-web.dropbox.com/upload?
name=sample.jpg&dest=upload&cookie_t=5Ot52QKDbDP....SsJ&t=5Ot5...apJ HTTP/1.1
----------------------------------------
HTTP/1.1 400 Bad Request
I used Firefox LiveHttpHeader to capture the headers as I do the login and upload file, and saw the post to file upload actually is doing this (and reflect in the code):
https://dl-web.dropbox.com/chunked_upload?
name=tmp1.jpg
&chunk=0
&chunks=1
&bjar=W3sic2Vzc1..............Q%253D%253D
&blid=AAAw4tn................2cDxA
&cookie_t=32yq........nw6c34o
&dest=
&t=32yqVof........c34o
&reported_total_size=5611
&upload_id=1BKGRRP5TpCEjcWSu5tmpQ
&offset=0
So apparrently I missed some param but can't figure out what. The access token seems to be valid as I can see my account info in the return from a httpclinet post to https://www.dropbox.com/home, but the upload simply not working. Anyone has similar experience and getting HTTP 400 error ? .... Many Thanks !
Some code as below:
Constructor and main():
// constructor ...
public HttpClientExample() {
gcookies = new BasicCookieStore();
globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
// Create local HTTP context
ghttpContext = HttpClientContext.create();
ghttpContext.setCookieStore(gcookies);
//
redirectStrategy = new LaxRedirectStrategy(); // for http redirect ...
httpclient = HttpClients.custom()
.setDefaultRequestConfig(this.globalConfig)
.setDefaultCookieStore(this.gcookies)
.setRedirectStrategy(redirectStrategy)
.build();
} // constructor ...
public static void main(String[] args) throws Exception {
HttpClientExample myhttp = new HttpClientExample();
try {
this.localConfig = RequestConfig.copy(this.globalConfig)
.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
.build();
String requestToken = this.getRequestToken(httpclient, loginurl);
theAccessToken = this.postForAccessToken(requestToken, loginurl);
String localFileTopassIn = this.localPath ;
this.postToUpload(httpclient, this.theAccessToken, localFileTopassIn , this.dropboxFolderOnlyName);
}
}
Get the request token:
private String getRequestToken(HttpClient client, String theURL) throws Exception {
HttpGet httpget = new HttpGet(theURL);
httpget.setConfig(localConfig);
httpget.setHeader("Connection", "keep-alive");
System.out.println("\nexecuting request:" + httpget.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(gvcString) == -1) ) {
gvc = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(tString) == -1) ) {
requestToken = aCookie.getValue();
}
}
System.out.println("Request Token: " + requestToken );
return requestToken;
}
postForAccessToken:
private String postForAccessToken(HttpClient client, String requestToken, String theURL) throws Exception{
/*
* Send a post together with request token and my login to get accessToken ...
*/
HttpPost httppost = new HttpPost(theURL); // loginurl);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
List params = new LinkedList();
params.add(new BasicNameValuePair("login_email", myemail));
params.add(new BasicNameValuePair("login_password", mypasswd));
params.add(new BasicNameValuePair("t", requestToken));
HttpEntity postentity = new UrlEncodedFormEntity(params);
httppost.setEntity(postentity);
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(tString) == -1) ) {
theAccessToken = aCookie.getValue();
}
}
System.out.println("Access Token: " + theAccessToken );
return theAccessToken;
}
postToUpload:
private String postToUpload(HttpClient client, String accessToken, String localFileInfo, String destPath) throws Exception{
String bjarString = "bjar";
String blidString = "blid";
String bjar=null;
String blid=null;
List cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(bjarString) == -1) ) {
bjar = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(blidString) == -1) ) {
blid = aCookie.getValue();
}
}
String[] fileNameArry = localFileInfo.split("(\\\\|/)");
String filename = fileNameArry[fileNameArry.length - 1]; // get the last part ...
URI uri = new URIBuilder()
.setScheme("https")
.setHost("dl-web.dropbox.com")
.setPath("/upload")
.setParameter("name", filename)
.setParameter("dest", destPath)
.setParameter("cookie_t", accessToken)
.setParameter("t", accessToken)
.build();
HttpPost httppost = new HttpPost(uri);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
FileBody bin = new FileBody(new File(localFileInfo));
StringBody comment = new StringBody("A binary file of some kind", ContentType.DEFAULT_BINARY);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("bin", bin)
.addPart("comment", comment)
.build();
httppost.setEntity(reqEntity);
// add header
httppost.setHeader("Host", "www.dropbox.com");
httppost.setHeader("User-Agent", USER_AGENT);
httppost.setHeader("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httppost.setHeader("Connection", "keep-alive");
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httppost.setHeader("Pragma", "no-cache");
httppost.setHeader("Cache-Control", "no-cache");
// add entity
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status
OAuth is the only way to use the Dropbox API. Once you have an OAuth access token (which you get by authenticating once, in this case with your account), you just need to do an HTTP PUT to https://api-content.dropbox.com/1/files_put/auto/<path> with the header Authorization: Bearer <token> and the contents of the file in the body.
Note that anyone who has your access token can also delete all your files, upload their personal DVD collection, etc. So it's not recommended that you share that access token.
There is files_get_temporary_upload_link:
Get a one-time use temporary upload link to upload a file to a Dropbox location.
This endpoint acts as a delayed upload. The returned temporary upload link may be used to make a POST request with the data to be uploaded. The upload will then be perfomed with the CommitInfo previously provided to get_temporary_upload_link but evaluated only upon consumption. Hence, errors stemming from invalid CommitInfo with respect to the state of the user's Dropbox will only be communicated at consumption time. Additionally, these errors are surfaced as generic HTTP 409 Conflict responses, potentially hiding issue details. The maximum temporary upload link duration is 4 hours. Upon consumption or expiration, a new link will have to be generated. Multiple links may exist for a specific upload path at any given time.
So you need to have an access token to call this function, but the uploader needs only the produced URL, without access to the rest of the Dropbox vault.

How to construct message header for a HEAD response with restlet

I'm trying to create a HEAD response with restlet. Unfortunatly there is ony a #Get annotation, but the restlet author states, that you have to use a #Get, and then compare the Method.
As the documentation/specification says, there can be no body, but only a message header.
Now how to create a message header that will be send to the server, because the following code does not work, it sends this headers: HTTP/1.1 204 No Content, Content-Length: 0
protected void addResponseHeader(String name, String value) {
Form responseHeaders = (Form)getResponse().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
if (responseHeaders == null) {
responseHeaders = new Form();
getResponse().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
}
responseHeaders.add(new Parameter(name, value));
}
The concrete code on server-side:
#Get
public void execute() {
if (Method.HEAD.equals(getMethod())) {
//optional: getResponse().getEntity().setMediaType(MediaType.TEXT_PLAIN);
getResponse().setStatus(Status.SUCCESS_OK, "hello head");
addResponseHeader("X-my-header", "value");
}
}
The client code:
#Test
public void head() {
Request request = new Request(Method.HEAD, url);
Response response = query(request);
assertEquals(Status.SUCCESS_OK, response.getStatus());
Form form = (Form)response.getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
assertEquals("value", form.getFirstValue("X-my-value")); // does fail because it is null
}
You just need to implement #Get for real : should work with a HTTP GET fine first. Then if you issue a HTTP HEAD, it will be handled automatically by the framework, nothing else to do on your side. Just focus on getting GET implemented correctly.