Zend Rest Api: putAction on POST method - zend-framework

I got a weird issue. I hope someone could help me.
I am new to Zend and I'm writing a RESTfull API.
When I run the curl command as POST method, it calls the putAction() function.
For example, I am run a curl command:
curl -X POST http://localhost/ws/user/post -v
Here is the response:
* About to connect() to localhost port 80 (#0)
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 80 (#0)
> POST /ws/user/post HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Mon, 22 Oct 2012 13:37:56 GMT
< Server: Apache/2.2.14 (Ubuntu)
< X-Powered-By: PHP/5.3.2-1ubuntu4.18
< Vary: Accept-Encoding
< Content-Length: 53
< Content-Type: text/html
<
* Connection #0 to host localhost left intact
"From putAction() updating the requested article"
Method = POST
* Closing connection #0
Here is the code:
[...]
public function postAction() {
echo 'Method = ' . $_SERVER['REQUEST_METHOD'];
if (!$id = $this->_getParam('id', false)) {
$this->sendResponse("Bad request. Id is missing", 400);
}
$this->sendResponse("From postAction() creating the requested article", 201);
}
public function putAction() {
echo 'Method = ' . $_SERVER['REQUEST_METHOD'];
$this->sendResponse("From putAction() updating the requested article");
}
[...]
Any ideas ?
EDIT:
I realized that I put this code in my bootstrap:
public function _initRestRoute() {
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$restRoute = new Zend_Rest_Route($front, array(), array(
'ws',
));
$router->addRoute('rest', $restRoute);
}
When I comment it, it works.
Any explanations ? Thanks!

You shouldn't be having http://localhost/ws/user/post in your request while using the Zend_Rest_Route. This route interprets /user/post as parameters and changes action from post to put. Try http://localhost/ws instead.
See Zend/Rest/Route.php line 208.

Related

Play framework 2.5 will not stream the request into the response

Hi I have a requirement to use play framework 2.5 (scala) to receive a large request body, then transform it and then stream it straight back out.
So far I've been unable to get the request stream to be sent out correctly using a chunked response (even untransformed).
Code example:
def endpointA = EssentialAction { requestHeader =>
Accumulator.source.map { source: Source[ByteString, _] =>
Ok.chunked(source)
}
}
POSTing data to the endpoint with curl does not output the posted data as expected and just results in the error below. I confirmed with wireshark that no response body is sent.
curl -v --data 'hello' -H "Connection: Keep-Alive" -H "Keep-Alive: 300" -H "Content-type: text/plain" http://localhost:9584/binding-tariff-admin/upload-csv
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9584 (#0)
> POST /binding-tariff-admin/endpoint-a HTTP/1.1
> Host: localhost:9584
> User-Agent: curl/7.64.1
> Accept: */*
> Connection: Keep-Alive
> Keep-Alive: 300
> Content-type: text/plain
> Content-Length: 5
>
* upload completely sent off: 5 out of 5 bytes
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
< Cache-Control: no-cache,no-store,max-age=0
< Content-Security-Policy: default-src 'self' 'unsafe-inline' *.s3.amazonaws.com www.google-analytics.com data:
< X-Permitted-Cross-Domain-Policies: master-only
< Content-Type: application/octet-stream
< Date: Wed, 19 Feb 2020 10:15:36 GMT
<
* transfer closed with outstanding read data remaining
* Closing connection 0
curl: (18) transfer closed with outstanding read data remaining
Also, if I change the code to return a stream I create myself, it works fine:
val testStream: Source[ByteString, NotUsed] = Source(List("hello")).map(ByteString.apply)
Is there something fundamentally wrong with what I'm trying to do here? I have seen other stack overflow examples with people suggesting this should be possible, e.g.
Play Framework Scala: How to Stream Request Body
I also tried using the verbatimBodyParser method described in the link but got the same results.
Thanks!
NFV

Does jetty overwrite custom http status code ?

I am trying to develop a rest api for my service wherein I set custom http status code depending on authorisation failure. But when I test it out using curl I am receiving 404 instead of 403. I am perplexed as to what might be causing this? Please help.
This is what I see from curl output or swagger UI:
root#ubuntu:~# curl -X GET http://localhost:8082/mr/v1/topic/bhakk -v
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8082 (#0)
> GET /mr/v1/topic/bhakk HTTP/1.1
> Host: localhost:8082
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Mon, 07 May 2018 22:00:10 GMT
< Exception: serviceBlockedException
< Content-Type: application/vnd.kafka.v1+json
< Content-Length: 83
< Server: Jetty(9.2.z-SNAPSHOT)
<
* Connection #0 to host localhost left intact
{"error_code":40301,"message":"This service does not have access to the resource."}
Here is the code:
public Collection<String> list(#HeaderParam("x-nssvc-serviceid") String serviceID) {
Date now = new java.util.Date();
if (! ctx.getSecurityRestrictions().isServiceAllowed(uri, httpHeaders, "Describe", "Cluster", "kafka-cluster"))
throw Errors.serviceBlockedException(ctx,httpServletResponse);
List<String> topicsCopy = new ArrayList<String>(topics);
for (Iterator<String> iterator = topicsCopy.iterator(); iterator.hasNext();) {
String topic = iterator.next();
if (! ctx.getSecurityRestrictions().hasAccess (serviceId, "Describe", "Topic", topic)) {
iterator.remove();
}
}
return topicsCopy;
}
public static RestException serviceBlockedException(Context ctx,HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Exception","serviceBlockedException");
httpServletResponse.setStatus(Status.FORBIDDEN.getStatusCode()); <----// here i am setting status code.
return new RestNotFoundException(SERVICE_ID_BLOCKED_MESSAGE, SERVICE_ID_BLOCKED_ERROR_CODE);
}
Kafka sets the Response 404 status in its RestNotFoundException
See: https://github.com/confluentinc/rest-utils/blob/master/core/src/main/java/io/confluent/rest/exceptions/RestNotFoundException.java

Browser ignores new port from nginx redirect

I need to create a http redirect via nginx. The goal is:
http://subdomain.domain.tld/path -> https://subdomain.domain.tld/path
http://subdomain.domain.tld:8090/path -> https://subdomain.domain.tld/path
This is my nginx configuration:
server {
listen 80;
listen 8090;
server_name subdomain.domain.tld;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name subdomain.domain.tld;
[...]
}
The first case works correctly. The second case technically, but not at the client browsers. If I start a request via cURL everything looks fine:
curl -v "http://subdomain.domain.tld:8090/path"
* About to connect() to subdomain.domain.tld port 8090 (#0)
* Trying XX.XX.XX.XX...
* Adding handle: conn: 0x1c94010
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x1c94010) send_pipe: 1, recv_pipe: 0
* Connected to subdomain.domain.tld (89.15.246.188) port 8090 (#0)
> GET /oath HTTP/1.1
> User-Agent: curl/7.30.0
> Host: subdomain.domain.tld:8090
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
* Server nginx is not blacklisted
< Server: nginx
< Date: Wed, 08 Jun 2016 10:28:15 GMT
< Content-Type: text/html
< Content-Length: 178
< Connection: keep-alive
< Location: https://subdomain.domain.tld/path
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
But if I open the url http://subdomain.domain.tld:8090/path in my browser I get the url https://subdomain.domain.tld:8090/path. The browser switch to https but use the old port.
I checked it with Google Chrome, Firefox, Internet Explorer and Apple Safari. The result is the same and I dont understand why?
You've got HSTS (Strict-Transport-Security header). So browsers do exactly what this policy requires:
https://www.rfc-editor.org/rfc/rfc6797#section-8.3
8.3.5 [...] The UA MUST replace the URI scheme with "https", and [...] if the URI contains an explicit port component that is not equal to "80", the port component value MUST be preserved;…

play scala 2.4.3 redicrect not working

I'm trying the Reverse routing sample code
Here are my routes
GET /hello/:name controllers.Application.hello(name)
GET /bob controllers.Application.helloBob
and my codes
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
def hello(name: String) = Action {
Ok("Hello " + name + "!")
}
I can get hello response
$ curl -v localhost:9001/hello/play
Hello play!
But, can't get "Bob" response after redirect?
$ curl -v localhost:9001/bob
* Trying ::1...
* Connected to localhost (::1) port 9001 (#0)
> GET /bob HTTP/1.1
> Host: localhost:9001
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 303 See Other
< Location: /hello/Bob
< Date: Fri, 18 Sep 2015 03:19:04 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
The path component of a URI is case sensitive. Check it.
try
curl -v localhost:9001/hello/Bob
Update
You code is correct (verified on my project) and you show the correct log - it prints 303 code. I think, you just need to say curl to follow redirect, like this
curl -L localhost:9000/bob

curl command line equivalent to this perl code

I want to write a curl command for a POST request equivalent to this Perl code:
use strict;
use warnings;
use LWP::UserAgent;
my $base = 'http://www.uniprot.org/mapping/';
my $params = {
from => 'ACC',
to => 'P_REFSEQ_AC',
format => 'tab',
query => 'P13368'
};
my $agent = LWP::UserAgent->new();
push #{$agent->requests_redirectable}, 'POST';
my $response = $agent->post($base, $params);
$response->is_success ?
print $response->content :
die 'Failed, got ' . $response->status_line .
' for ' . $response->request->uri . "\n";
I tried with (and many other variants) :
curl -X POST -H "Expect:" --form "from=ACC;to=P_REFSEQ_AC;format=tab; query=P13368" http://www.uniprot.org/mapping/ -o out.tab
The Perl code retrieves the expected result, but the curl command line does not. It retrieves the web page from "http://www.uniprot.org/mapping/" but does not make the POST request.
I looked for an error in the response header, but didn't find anything suspicious.
> POST http://www.uniprot.org/mapping/ HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: www.uniprot.org
> Accept: */*
> Proxy-Connection: Keep-Alive
> Content-Length: 178
> Content-Type: multipart/form-data; boundary=----------------------------164471d8347f
>
} [data not shown]
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: Apache-Coyote/1.1
< Vary: User-Agent
< Vary: Accept-Encoding
< X-Hosted-By: European Bioinformatics Institute
< Content-Type: text/html;charset=UTF-8
< Date: Wed, 05 Aug 2015 20:32:00 GMT
< X-UniProt-Release: 2015_08
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: origin, x-requested-with, content-type
< X-Cache: MISS from localhost
< X-Cache-Lookup: MISS from localhost:3128
< Via: 1.0 localhost (squid/3.1.20)
< Connection: close
<
I spent almost three days looking for a solution in the web, but nothing is working for me.
It looks like the server expects the data as application/x-www-form-urlencoded and not as multipart/form-data as you do with the --form argument. The following should work:
curl -v -L --data \
"from=ACC&to=P_REFSEQ_AC&format=tab&query=P13368" \
http://www.uniprot.org/mapping/ -o out.tab
With --data you get the expected content-type header, but you must do the encoding yourself. With -L curl follows a redirect which is needed here to get the resulting data.
The -X POST option is not needed since POST is the default method when sending data. And -H "Expect:" is not needed either.