How can DELETE requests be made with a Dart HttpClient? - dart

If you're using a Dart HttpClient (which provides an HttpClientRequest) to make requests from a server to another server, as far as I can tell the only HTTP methods available are GET and POST (corresponding, respectively, to the post/postUrl and get/getUrl functions). Is there also a way to make PUT and DELETE requests?

You should be able to do with this with the open method which allows you to use any HTTP verb:
client.open('delete', 'http://example.com', '8080', '/test');
If you look at the HttpClient source you'll see that the get and post methods are just aliases for open anyway:
Future<HttpClientRequest> post(String host,
int port,
String path) {
return open("post", host, port, path);
}

Related

How can I force the .NET ASMX WSDL generation to change a soap:address location from http to https?

Using VB.NET asmx project, which is hosted behind SSL offload, I need to change the generated WSDL to show https for the soap:address.
from: <soap:address location="http://example.com/example.asmx"/>
to: <soap:address location="https://example.com/example.asmx"/>
preferably outside of code so we can influence in the build process.
It depends what system are you using for generating the wsdl.
You shared that you are using VB.NET but it does not narrow down enough to answer your question a 100%. If you can show some code then we could help hopefully. Also as far as I remember, the location in the WSDL file is the same as the client is accessing it (the URL where it reaches). Meaning that as the offloading happens elsewhere the location could always be http.
Without further information I see three options for you:
Configure the TLS offloader to redirect the queries from http to httpS. (This is also a recommended setting from a security point of view.)
Where the offloading is happening use a solution to replace the content of the response. (This has the advantage of being specific to the environment.)
Use self singed certificate on the internal application as well, and therefore the address will be generated correctly. (This could be a bit tougher nut to crack, but has the benefit of not being dependent on other configuration and having to modify that configuration for every environment from development to live.)
In c# it could be done in code https://learn.microsoft.com/en-us/archive/blogs/kaevans/modify-a-web-services-wsdl-using-a-soapextensionreflector and is qite complicated. If you have a developer machine, then you need to use TLS as well... but here you go:
using System;
using System.Web.Services.Description;
namespace Msdn.Web.Services.Samples
{
public class HttpsReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
//no-op
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
SoapAddressBinding binding = extension as SoapAddressBinding;
if (null != binding)
{
binding.Location = binding.Location.Replace("https://", "https://");
}
}
}
}
}
}
}

dart compute Illegal argument in isolate message

I am using compute to do some work while keeping the UI running. The compute was working until I added another http call before it.
The working code is as follow
final ListRequest request =
ListRequest(baseUrl: env['SERVER_URL']!, path: '/Items');
_mainController.updateListItems(
await compute(_service.getItems, request));
I read some articles saying the function compute calls should be a top level function or a static function. However, the getItems is an instance function and there was no exception.
Recently I added a few lines and the code became
final Filter? filter = await _service.getFilter();
final ListRequest request =
ListRequest(baseUrl: env['SERVER_URL']!, path: '/Items');
request.filter = filter;
_mainController.updateListItems(
await compute(_service.getItems, request));
getFilter is a http call to retrieve some filter parameters from the backend.
Then I got the following error
Invalid argument(s): Illegal argument in isolate message: (object extends NativeWrapper - Library:'dart:io' Class: _SecureFilterImpl#13069316)
My dart and flutter versions are
Dart SDK version: 2.15.1 (stable)
Flutter 2.8.1
Thank you
=========================================================
Update
The Filter is
Filter {
String? itemLocationSuburb;
String? itemLocationPostcode;
}
Your _service service presumably contains a HttpClient. When you make a request through this client, it opens a connection to the HTTP server, and may maintain the connection after the request completes.
The HttpClient cannot be sent through a SendPort when it has open connections, but it is included in the scope of the getItems method.
To work around this issue, you can do one of the following:
Disable persistent connections with the HttpClientRequest.persistentConnection property
Make a new HttpClient to send through the compute function every time
Implement a long-lived background isolate to maintain its own HttpClient
Use the HttpClient in the main isolate, and only perform other work like parsing with compute (there's no significant benefit to using an isolate to make HTTP requests anyway)

ASP Web API POST request with CORS and IE9 (XDomainRequest object)

I've been going crazy here trying to get jquery.ajax to work with ie9. So I have a ASP Web API 2 Rest API that implements CORS. CORS requests from all browsers work. IE9 didnt work since it uses the XDomainRequest. I managed to get it too work by making a custom implementation of ajaxTransport for IE9.
Right now GET requests seem to work fine. But when I do a post request from IE9 I get a HTTP error 415 - unsuportted media type.
I've set the content-type to:"application/json" and I've also tried "application/x-www-form-urlencoded", but from what I understood XDomainRequest doesnt support everything with custom headers? Does anybody know if something specific needs to be setup on the WebAPI or do I need to tweak the request?
My request looks like this:
$.ajax({
url: hostname + "/api/DDC/Book",
type: "POST",
contentType: "application/json",
data: {
DealID: function () {
return viewModel.get("DealID");
},
LocationID: function () {
return viewModel.get("LocationID");
},
Time: function () {
return viewModel.get("selectedDateTime.Time");
}
}
})
On the server I have this:
[HttpPost("DDC/Book")]
[EnableCors(origins: "*", headers: "*", methods: "POST, GET, OPTIONS, PUT, DELETE")]
public dynamic Post(BookModel model)
{
.........
When I analyze the failed request in the IE debugger this are the request headers that get sent out:
Key Value
Request POST //api/DDC/Book HTTP/1.1
Accept */*
Origin http://myurl.com
Accept-Language hr-HR
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host www.somehost.com
Content-Length 55
DNT 1
Connection Keep-Alive
Cache-Control no-cache
I'm really losing all hope here and IE is making my go crazy (damn you Microsoft :D ), so any help or advice is much appriciated.
EDIT: From more reasearch I found out that WebAPI requires a content-type to work and XDomainRequest doesnt send out one. So the only solution I see is too tweak my webapi to have a default content-type when nothing is set. Don't know how to this yet though
EDIT2: Hacked my way through temporarily by transforming all my POSTs, to GETs, dont know how smart is this, but I see no bigger problem with it now, so it will do until I fix the problem
Managed to solve it myself. As pointed by Ray Nicholus when there is no Content-Type ASP Web API defaults to an "application/octet-stream" Content-Type. I need a default of "application/x-www-form-urlencoded".
I managed to achive this by writing my own simple message handler that checks an incoming requests "Content-Type" and if nothing is present it adds an "application/x-www-form-urlencoded" one.
This is the code:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentType == null)
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
UPDATE:
As written by Robert Christ in the comment below I am extending the answer a bit for those who have not worked with message handlers before:
For those who don't understand at first glance, DelegatingHandlers
allow you to modify requests / response objects before they really hit
the WebAPI framework internals. Nothing else in the framework really
lets you modify the incoming request before model binding, without
actually writing custom model binders (eugh). so instead, here, you
can sniff out a null content type (which is guaranteed by shortcomings
in the XDomainRequest spec), update it to xml or json, and you will be
able to parse the incoming request correctly.
After you have written a message handler you need to register it with WebAPI. You do that in the WebApiConfig class:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
// Rest of your code
}
}
Just to confirm what you have already edited into your question over several updates: yes, XDomainRequest does not include a Content-Type header in the request. As you may know by now, you can't set any headers via this transport.
The lack of a Content-Type is particularly problematic for most server-side frameworks, as this means they will be unable to parse the content of the response automatically. In the absence of a Content-Type header, RFC 2616 says the body is assumed to be application/octet-stream, which is likely not what you want in this case. So, you'll need to "manually" parse the request body server-side by hard-coding the expected Content-Type for the associated request in this case.
I would strongly recommend you not simply convert all of your POSTs to GETs. GET requests should be "safe", per RFC 2616. By simply renaming all of your POSTs to GETs, you are no longer following the defined and accepted semantics of GET requests. In other words, don't do this.
Dennis' answer above uses async which is only available in .NET 4.5. For .NET 4 and possibly lower, use the following delegating handler instead:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null)
{
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
}
return base.SendAsync(request, cancellationToken);
}
}
Also, don't forget your USING statements, you will need:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

Https: Hide controller method from http

Ok, so we have the RequireHttpsAttribute that we can use to ensure that a controller/controller method can only be called over SSL. In the case that we try to hit the method over HTTP, the server issues a 302 to the HTTPS version of the same controller (method).
This implies to my users that it is acceptable to issue the first request insecurely in the first place. I don't feel that this is acceptable. Before I trot out an attribute that issues a 404/500 status code in the case that the HTTP version is hit, does such an attribute already exist?
Before I trot out an attribute that issues a 404/500 status code in
the case that the HTTP version is hit, does such an attribute already
exist?
No, such attribute doesn't exist out of the box.
If the simply act of requesting the page using HTTP is not compromising any user data, I'd say the redirect should be enough and a perfect approach for your scenario. Why bother user with things we can take care of?
This implies to my users that it is acceptable to issue the first
request insecurely in the first place. I don't feel that this is
acceptable. Before I trot out an attribute that issues a 404/500
status code in the case that the HTTP version is hit, does such an
attribute already exist?
If you don't want your application to work at all for these URLs using http:// instead of https://, don't serve anything at all (404 or no connection).
Note that it's ultimately the user's responsibility to check that SSL/TLS is used (and used correctly with a valid certificate). Make sure the links to those address use https:// indeed, and that the users expect https:// to be used, at least for the start page. You could consider using HSTS if their browser support it (or possibly permanent redirects to the entry point that would be cached).
From another comment:
I don't want any info about the url leaked in any way to any third parties
Once the request has been made using this http:// URL from the client, there's little point doing anything on the server. It's too late: an eavesdropper could have seen the request. (If your own page doesn't link to external websites, they wouldn't see that address in the referrer either.)
Even if your server doesn't even listen on the plain HTTP port, an active MITM attacker (or more simply, a proxy) could potentially listen to that request and get the URL, without it even reaching your server.
Again: make sure your users expect https:// to be used, and once they're on a secure page, make sure your links/form actions to other sections of your site all use https://.
So for reference, here's my new attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true,
AllowMultiple = false)]
public class HttpsOnlyAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly bool disableInDebug;
public HttpsOnlyAttribute(bool disableInDebug = false)
{
this.disableInDebug = disableInDebug;
}
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
#if DEBUG
if (disableInDebug) return;
#endif
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var context = filterContext.HttpContext;
var request = context.Request;
var isSecure = request.IsSecureConnection;
if (!isSecure)
{
throw new HttpException(404, "Not found");
}
}
}

Using codec file extensions with OpenRasta returns 404

When using codec uri file extensions with OpenRasta, OR can't resolve the uri and returns a 404. Without the file extension all works ok.
The codecs are defined for the object resource and I'm using both XmlDataContract and JsonDataContract. Using neither the .xml or .json extension works, this is for both InMemoryHost (which we're using for testing) and ASP.Net (IIS7, integrated mode).
Codec configuration:
ResourceSpace.Has.ResourcesOfType<object>()
.WithoutUri
.AsXmlDataContract()
.And.AsJsonDataContract();
Is there anything else that needs to be done to make uri file extensions work?
You need to register the ContentTypeExtensionUriDecorator as a UriDecorator in OpenRasta in order to expose the .xml, .json functionallity.
The below example should allow you to make http requests to:
GET /home.json
GET /home.xml
public class RastaConfig : IConfigurationSource
{
public void Configure()
{
using(OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.UriDecorator<ContentTypeExtensionUriDecorator>();
ResourceSpace.Has.ResourceOfType<Home>()
.AtUri("/home")
.HandledBy<HomeHandler>()
.AsXmlDataContract()
.And.AsJsonDataContract();
}
}
}
This is because noramlly the client will add an HTTP Accept header to define the content types it supports and is interested in.
For more information you can read about Content Negotiation (often referred to as conneg) on the web.
OpenRasta will then select the return content type based on the client 's preference in the HTTP Accept header.
Hope this helps.

Resources