Merge changes from Javier
- update on RESTbuck examples - new example - fixed bad typo in WSF_REQUEST Reverted some changes such as - http_client_response: keep the headers as a list to handle multiple message-value with same message-name Fixed simple and simple_file example Improved HTTP_HEADER Changed libcurl implementation for http client - now the header from the context really overwrite any of the session headers - better design which is more strict, and remove any doubt about context's header usage
This commit is contained in:
Submodule contrib/ise_library/cURL updated: f17f785ee3...2b7043f670
Submodule contrib/library/text/parser/json updated: 5ec1bdd2ea...24d08d4fce
@@ -1,72 +0,0 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
RESTBUCK_CLIENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
h: LIBCURL_HTTP_CLIENT
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
s: READABLE_STRING_8
|
||||
j: JSON_PARSER
|
||||
id: detachable STRING
|
||||
do
|
||||
create h.make
|
||||
sess := h.new_session ("http://127.0.0.1")
|
||||
s := "[
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]"
|
||||
|
||||
if attached sess.post ("/order", Void, s) as r then
|
||||
if attached r.body as m then
|
||||
create j.make_parser (m)
|
||||
|
||||
if j.is_parsed and attached j.parse_object as j_o then
|
||||
if attached {JSON_STRING} j_o.item ("id") as l_id then
|
||||
id := l_id.item
|
||||
end
|
||||
print (m)
|
||||
io.put_new_line
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if id /= Void and then attached sess.get ("/order/" + id, Void) as r then
|
||||
print (r.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
feature -- Access
|
||||
|
||||
feature -- Change
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
invariant
|
||||
-- invariant_clause: True
|
||||
|
||||
end
|
||||
@@ -1,51 +0,0 @@
|
||||
Restbuck Eiffel Implementation based on the book of REST in Practice
|
||||
|
||||
|
||||
Verb URI or template Use
|
||||
POST /order Create a new order, and upon success, receive a Locationheader specifying the new order<65>s URI.
|
||||
GET /order/{orderId} Request the current state of the order specified by the URI.
|
||||
PUT /order/{orderId} Update an order at the given URI with new information, providing the full representation.
|
||||
DELETE /order/{orderId} Logically remove the order identified by the given URI.
|
||||
|
||||
|
||||
How to Create an order
|
||||
|
||||
* Uri: http://localhost:8080/order
|
||||
* Method: POST
|
||||
* Note: you will get in the response the "location" of the new your order.
|
||||
* HEADERS:
|
||||
|
||||
Content-Type: application/json
|
||||
|
||||
* Example CONTENT
|
||||
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
How to Read an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: GET
|
||||
|
||||
|
||||
|
||||
|
||||
How to Update an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: PUT
|
||||
|
||||
|
||||
How to Delete an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: DELETE
|
||||
|
||||
170
examples/restbucksCRUD/client/src/restbuck_client.e
Normal file
170
examples/restbucksCRUD/client/src/restbuck_client.e
Normal file
@@ -0,0 +1,170 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
RESTBUCK_CLIENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
h: LIBCURL_HTTP_CLIENT
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
resp : HTTP_CLIENT_RESPONSE
|
||||
l_location : detachable READABLE_STRING_8
|
||||
body : STRING
|
||||
do
|
||||
create h.make
|
||||
sess := h.new_session ("http://127.0.0.1:8080")
|
||||
-- Create Order
|
||||
print ("%N Create Order %N")
|
||||
resp := create_order (sess)
|
||||
|
||||
-- Read the Order
|
||||
print ("%N Read Order %N")
|
||||
l_location := resp.headers.at ("Location")
|
||||
resp := read_order (sess, l_location)
|
||||
|
||||
|
||||
-- Update the Order
|
||||
|
||||
if attached resp.body as l_body then
|
||||
body := l_body.as_string_8
|
||||
body.replace_substring_all ("takeAway", "in Shop")
|
||||
print ("%N Update Order %N")
|
||||
resp := update_order (sess, l_location, body)
|
||||
end
|
||||
end
|
||||
|
||||
update_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8; a_body : STRING) : HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
l_headers: HASH_TABLE [READABLE_STRING_8,READABLE_STRING_8]
|
||||
do
|
||||
create Result.make
|
||||
if attached uri as l_uri then
|
||||
sess.set_base_url (l_uri)
|
||||
Result := sess.put ("", Void, a_body )
|
||||
if attached Result as r then
|
||||
-- Show headers
|
||||
l_headers := r.headers
|
||||
from
|
||||
l_headers.start
|
||||
until
|
||||
l_headers.after
|
||||
loop
|
||||
print (l_headers.key_for_iteration)
|
||||
print (":")
|
||||
print (l_headers.item_for_iteration)
|
||||
l_headers.forth
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
-- Show body
|
||||
print (r.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
read_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8) : HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
l_headers: HASH_TABLE [READABLE_STRING_8,READABLE_STRING_8]
|
||||
do
|
||||
create Result.make
|
||||
if attached uri as l_uri then
|
||||
sess.set_base_url (l_uri)
|
||||
Result := sess.get ("", Void)
|
||||
if attached Result as r then
|
||||
-- Show headers
|
||||
l_headers := r.headers
|
||||
from
|
||||
l_headers.start
|
||||
until
|
||||
l_headers.after
|
||||
loop
|
||||
print (l_headers.key_for_iteration)
|
||||
print (":")
|
||||
print (l_headers.item_for_iteration)
|
||||
l_headers.forth
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
-- Show body
|
||||
print (r.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
create_order (sess: HTTP_CLIENT_SESSION) : HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
s: READABLE_STRING_8
|
||||
j: JSON_PARSER
|
||||
id: detachable STRING
|
||||
context : HTTP_CLIENT_REQUEST_CONTEXT
|
||||
l_headers: HASH_TABLE [READABLE_STRING_8,READABLE_STRING_8]
|
||||
do
|
||||
s := "[
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]"
|
||||
|
||||
create context.make
|
||||
context.headers.put ("application/json", "Content-Type")
|
||||
Result := sess.post ("/order", context, s)
|
||||
if attached Result as r then
|
||||
-- Show the Headers
|
||||
l_headers := r.headers
|
||||
from
|
||||
l_headers.start
|
||||
until
|
||||
l_headers.after
|
||||
loop
|
||||
print (l_headers.key_for_iteration)
|
||||
print (":")
|
||||
print (l_headers.item_for_iteration)
|
||||
l_headers.forth
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
|
||||
-- Show the Response body
|
||||
if attached r.body as m then
|
||||
create j.make_parser (m)
|
||||
if j.is_parsed and attached j.parse_object as j_o then
|
||||
if attached {JSON_STRING} j_o.item ("id") as l_id then
|
||||
id := l_id.item
|
||||
end
|
||||
print (m)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
invariant
|
||||
-- invariant_clause: True
|
||||
|
||||
end
|
||||
293
examples/restbucksCRUD/readme.md
Normal file
293
examples/restbucksCRUD/readme.md
Normal file
@@ -0,0 +1,293 @@
|
||||
Restbuck Eiffel Implementation based on the book of REST in Practice
|
||||
====================================================================
|
||||
This is an ihmplementation of CRUD pattern for manipulate resources, this is the first step to use
|
||||
the HTTP protocol as an application protocol instead of a transport protocol.
|
||||
|
||||
Restbuck Protocol
|
||||
-----------------
|
||||
|
||||
<table>
|
||||
<TR><TH>Verb</TH> <TH>URI or template</TH> <TH>Use</TH></TR>
|
||||
<TR><TD>POST</TD> <TD>/order</TD> <TD>Create a new order, and upon success, receive a Locationheader specifying the new order's URI.</TD></TR>
|
||||
<TR><TD>GET</TD> <TD>/order/{orderId}</TD> <TD>Request the current state of the order specified by the URI.</TD></TR>
|
||||
<TR><TD>PUT</TD> <TD>/order/{orderId}</TD> <TD>Update an order at the given URI with new information, providing the full representation.</TD></TR>
|
||||
<TR><TD>DELETE</TD> <TD>/order/{orderId}</TD> <TD>Logically remove the order identified by the given URI.</TD></TR>
|
||||
</table>
|
||||
|
||||
Resource Represenation
|
||||
----------------------
|
||||
The previous tables shows a contrat, the URI or URI template, allows us to indentify resources, now we will chose a
|
||||
representacion, for this particular case we will use JSON.
|
||||
|
||||
Note: <br/>
|
||||
1. *A resource can have multiple URIs*.<br/>
|
||||
2. *A resource can have multiple Representations*.<br/>
|
||||
|
||||
RESTBUCKS_SERVER
|
||||
----------------
|
||||
This class implement the main entry of our REST CRUD service, we are using a default connector (Nino Connector,
|
||||
using a WebServer written in Eiffel).
|
||||
We are inheriting from URI_TEMPLATE_ROUTED_SERVICE, this allows us to map our service contrat, as is shown in the previous
|
||||
table, the mapping is defined in the feature setup_router, this also show that the class ORDER_HANDLER will be encharge
|
||||
of to handle different type of request to the ORDER resource.
|
||||
|
||||
|
||||
class
|
||||
RESTBUCKS_SERVER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
URI_TEMPLATE_ROUTED_SERVICE
|
||||
|
||||
DEFAULT_SERVICE
|
||||
-- Here we are using a default connector using the default Nino Connector,
|
||||
-- but it's possible to use other connector (CGI or FCGI).
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize the router (this will have the request handler and
|
||||
-- their context).
|
||||
do
|
||||
initialize_router
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
create_router
|
||||
do
|
||||
create router.make (2)
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
order_handler: ORDER_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create order_handler
|
||||
router.map_with_request_methods ("/order", order_handler, <<"POST">>)
|
||||
router.map_with_request_methods ("/order/{orderid}", order_handler, <<"GET", "DELETE", "PUT">>)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- I'm using this method to handle the method not allowed response
|
||||
-- in the case that the given uri does not have a corresponding http method
|
||||
-- to handle it.
|
||||
local
|
||||
h : HTTP_HEADER
|
||||
l_description : STRING
|
||||
l_api_doc : STRING
|
||||
do
|
||||
if req.content_length_value > 0 then
|
||||
req.input.read_string (req.content_length_value.as_integer_32)
|
||||
end
|
||||
create h.make
|
||||
h.put_status ({HTTP_STATUS_CODE}.method_not_allowed)
|
||||
h.put_content_type_text_plain
|
||||
l_api_doc := "%NPlease check the API%NURI:/order METHOD: POST%NURI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
|
||||
l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc
|
||||
h.put_content_length (l_description.count)
|
||||
h.put_current_date
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
|
||||
res.write_header_text (h.string)
|
||||
res.write_string (l_description)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
How to Create an order with POST
|
||||
--------------------------------
|
||||
|
||||
Here is the convention that we are using:
|
||||
POST is used for creation and the server determines the URI of the created resource.
|
||||
If the request POST is SUCCESS, the server will create the order and will response with
|
||||
201 CREATED, the Location header will contains the newly created order's URI,
|
||||
if the request POST is not SUCCESS, the server will response with
|
||||
400 BAD REQUEST, the client send a bad request or
|
||||
500 INTERNAL_SERVER_ERROR, when the server can deliver the request.
|
||||
|
||||
POST /order HTTP/1.1
|
||||
Host: 127.0.0.1:8080
|
||||
Connection: keep-alive
|
||||
Content-Length: 196
|
||||
Origin: chrome-extension://fhjcajmcbmldlhcimfajhfbgofnpcjmb
|
||||
Content-Type: application/json
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip,deflate,sdch
|
||||
Accept-Language: es-419,es;q=0.8,en;q=0.6
|
||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
|
||||
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Status 201 Created
|
||||
Content-Type application/json
|
||||
Content-Length 123
|
||||
Location http://localhost:8080/order/1
|
||||
Date FRI,09 DEC 2011 20:34:20.00 GMT
|
||||
|
||||
{
|
||||
"location" : "takeAway",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
|
||||
How to Read an order with GET
|
||||
-----------------------------
|
||||
Using GET to retrieve resource information.
|
||||
If the GET request is SUCCESS, we response with 200 OK, and a representation of the order
|
||||
If the GET request is not SUCCESS, we response with 404 Resource not found
|
||||
If is a Conditional GET and the resource does not change we send a 304, Resource not modifed
|
||||
|
||||
GET /order/1 HTTP/1.1
|
||||
Host: 127.0.0.1:8080
|
||||
Connection: keep-alive
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip,deflate,sdch
|
||||
Accept-Language: es-419,es;q=0.8,en;q=0.6
|
||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
|
||||
If-None-Match: 6542EF270D91D3EAF39CFB382E4CEBA7
|
||||
|
||||
Response
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
Status 200 OK
|
||||
Content-Type application/json
|
||||
Content-Length 123
|
||||
Date FRI,09 DEC 2011 20:53:46.00 GMT
|
||||
etag 2ED3A40954A95D766FC155682DC8BB52
|
||||
|
||||
{
|
||||
"location" : "takeAway",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
|
||||
|
||||
How to Update an order with PUT
|
||||
-------------------------------
|
||||
A successful PUT request will not create a new resource, instead it will change the state of the resource identified by the current uri.
|
||||
If success we response with 200 and the updated order.
|
||||
404 if the order is not found
|
||||
400 in case of a bad request
|
||||
500 internal server error
|
||||
If the request is a Conditional PUT, and it does not mat we response 415, precondition failed.
|
||||
|
||||
Suposse that we had created an Order with the values shown in the _How to create an order with POST_
|
||||
But we change our decision and we want to stay in the shop.
|
||||
|
||||
|
||||
|
||||
PUT /order/1 HTTP/1.1
|
||||
Content-Length: 122
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
Expect: 100-Continue
|
||||
|
||||
{
|
||||
"location" : "in shop",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Status 200 OK
|
||||
Content-Type application/json
|
||||
Date FRI,09 DEC 2011 21:06:26.00 GMT
|
||||
etag 8767F900674B843E1F3F70BCF3E62403
|
||||
Content-Length 122
|
||||
|
||||
{
|
||||
"location" : "in shop",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
How to Delete an order with DELETE
|
||||
----------------------------------
|
||||
Here we use DELETE to cancel an order, if that order is in state where it can still be canceled.
|
||||
204 if is ok
|
||||
404 Resource not found
|
||||
405 if consumer and service's view of the resouce state is inconsisent
|
||||
500 if we have an internal server error
|
||||
|
||||
|
||||
DELETE /order/1 HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
|
||||
Status 204 No Content
|
||||
Content-Type application/json
|
||||
Date FRI,09 DEC 2011 21:10:51.00 GMT
|
||||
|
||||
If we want to check that the resource does not exist anymore we can try to retrieve a GET /order/1 and we will receive a
|
||||
404 No Found
|
||||
|
||||
GET /order/1 HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
|
||||
Response
|
||||
|
||||
HTTP/1.1 404 Not Found
|
||||
|
||||
Status 404 Not Found
|
||||
Content-Type application/json
|
||||
Content-Length 44
|
||||
Date FRI,09 DEC 2011 21:14:17.79 GMT
|
||||
|
||||
The following resource/order/1 is not found
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
1. [How to get a cup of coffe](http://www.infoq.com/articles/webber-rest-workflow)
|
||||
2. [Rest in Practice] (http://restinpractice.com/default.aspx)
|
||||
0
examples/restbucksCRUD/readme.txt
Normal file
0
examples/restbucksCRUD/readme.txt
Normal file
@@ -38,7 +38,7 @@ feature -- Conversion
|
||||
s_location ?= json.object (j.item (location_key), Void)
|
||||
s_status ?= json.object (j.item (status_key), Void)
|
||||
|
||||
create o.make (s_id, s_location, s_status)
|
||||
create o.make ("", s_location, s_status)
|
||||
|
||||
if attached {JSON_ARRAY} j.item (items_key) as l_val then
|
||||
l_array := l_val.array_representation
|
||||
@@ -87,7 +87,7 @@ feature -- Conversion
|
||||
jv: JSON_OBJECT
|
||||
do
|
||||
create Result.make
|
||||
Result.put (json.value (o.id), id_key)
|
||||
-- Result.put (json.value (o.id), id_key)
|
||||
Result.put (json.value (o.location), location_key)
|
||||
Result.put (json.value (o.status), status_key)
|
||||
from
|
||||
@@ -66,9 +66,9 @@ feature -- HTTP Methods
|
||||
local
|
||||
etag_util : ETAG_UTILS
|
||||
do
|
||||
if attached req.meta_variable ("HTTP_IF_NONE_MATCH") as if_none_match then
|
||||
if attached req.meta_string_variable ("HTTP_IF_NONE_MATCH") as if_none_match then
|
||||
create etag_util
|
||||
if if_none_match.as_string.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
if if_none_match.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
@@ -108,26 +108,31 @@ feature -- HTTP Methods
|
||||
-- If the request is a Conditional PUT, and it does not mat we response
|
||||
-- 415, precondition failed.
|
||||
local
|
||||
l_post: STRING
|
||||
l_put: STRING
|
||||
l_order : detachable ORDER
|
||||
id : STRING
|
||||
do
|
||||
req.input.read_string (req.content_length_value.as_integer_32)
|
||||
l_post := req.input.last_string
|
||||
l_order := extract_order_request(l_post)
|
||||
if l_order /= Void and then db_access.orders.has_key (l_order.id) then
|
||||
if is_valid_to_update(l_order) then
|
||||
if is_conditional_put (req, l_order) then
|
||||
update_order( l_order)
|
||||
compute_response_put (ctx, req, res, l_order)
|
||||
if attached req.orig_path_info as orig_path then
|
||||
id := get_order_id_from_path (orig_path)
|
||||
req.input.read_string (req.content_length_value.as_integer_32)
|
||||
l_put := req.input.last_string
|
||||
l_order := extract_order_request(l_put)
|
||||
if l_order /= Void and then db_access.orders.has_key (id) then
|
||||
l_order.set_id (id)
|
||||
if is_valid_to_update(l_order) then
|
||||
if is_conditional_put (req, l_order) then
|
||||
update_order( l_order)
|
||||
compute_response_put (ctx, req, res, l_order)
|
||||
else
|
||||
handle_precondition_fail_response ("", ctx, req, res)
|
||||
end
|
||||
else
|
||||
handle_precondition_fail_response ("", ctx, req, res)
|
||||
--| FIXME: Here we need to define the Allow methods
|
||||
handle_resource_conflict_response (l_put +"%N There is conflict while trying to update the order, the order could not be update in the current state", ctx, req, res)
|
||||
end
|
||||
else
|
||||
--| FIXME: Here we need to define the Allow methods
|
||||
handle_resource_conflict_response (l_post +"%N There is conflict while trying to update the order, the order could not be update in the current state", ctx, req, res)
|
||||
handle_bad_request_response (l_put +"%N is not a valid ORDER, maybe the order does not exist in the system", ctx, req, res)
|
||||
end
|
||||
else
|
||||
handle_bad_request_response (l_post +"%N is not a valid ORDER, maybe the order does not exist in the system", ctx, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -138,9 +143,9 @@ feature -- HTTP Methods
|
||||
etag_util : ETAG_UTILS
|
||||
do
|
||||
if attached retrieve_order (order.id) as l_order then
|
||||
if attached req.meta_variable ("HTTP_IF_MATCH") as if_match then
|
||||
if attached req.meta_string_variable ("HTTP_IF_MATCH") as if_match then
|
||||
create etag_util
|
||||
if if_match.as_string.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
if if_match.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
Result := True
|
||||
end
|
||||
else
|
||||
30
examples/simple/application.e
Normal file
30
examples/simple/application.e
Normal file
@@ -0,0 +1,30 @@
|
||||
note
|
||||
description : "simple application root class"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
local
|
||||
s: DEFAULT_SERVICE
|
||||
do
|
||||
create s.make_and_launch (agent execute)
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
res.write_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
|
||||
res.write_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
23
examples/simple/simple.ecf
Normal file
23
examples/simple/simple.ecf
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
|
||||
<target name="simple">
|
||||
<root class="APPLICATION" feature="make"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="http" location="..\..\library\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<cluster name="simple" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="simple_dotnet" extends="simple">
|
||||
<setting name="msil_generation" value="true"/>
|
||||
</target>
|
||||
</system>
|
||||
1
examples/simple/simple.rc
Normal file
1
examples/simple/simple.rc
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
13
examples/simple_file/home.html
Normal file
13
examples/simple_file/home.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<head>
|
||||
Eiffel REST services
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Welcome to the Eiffel REST services site, here you will find a lot of <br/>
|
||||
resources about REST and our solution
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
29
examples/simple_file/service_file.e
Normal file
29
examples/simple_file/service_file.e
Normal file
@@ -0,0 +1,29 @@
|
||||
note
|
||||
description : "simple application root class"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
SERVICE_FILE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
local
|
||||
s: DEFAULT_SERVICE
|
||||
do
|
||||
create s.make_and_launch (agent execute)
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: WSF_FILE_RESPONSE
|
||||
do
|
||||
create f.make_html ("home.html")
|
||||
res.put_response (f)
|
||||
end
|
||||
end
|
||||
24
examples/simple_file/service_file.ecf
Normal file
24
examples/simple_file/service_file.ecf
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
|
||||
<target name="service_file">
|
||||
<root class="SERVICE_FILE" feature="make"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="http" location="..\..\library\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<cluster name="service_file" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="service_file_dotnet" extends="service_file">
|
||||
<setting name="msil_generation" value="true"/>
|
||||
</target>
|
||||
</system>
|
||||
1
examples/simple_file/service_file.rc
Normal file
1
examples/simple_file/service_file.rc
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -12,16 +12,25 @@ inherit
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_url: READABLE_STRING_8; a_session: like session)
|
||||
make (a_url: READABLE_STRING_8; a_session: like session; ctx: like context)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
session := a_session
|
||||
url := a_url
|
||||
headers := session.headers.twin
|
||||
if ctx /= Void then
|
||||
context := ctx
|
||||
import (ctx)
|
||||
end
|
||||
ensure
|
||||
context_set: context = ctx
|
||||
ctx_header_set: ctx /= Void implies across ctx.headers as ctx_h all attached headers.item (ctx_h.key) as v and then v.same_string (ctx_h.item) end
|
||||
end
|
||||
|
||||
session: HTTP_CLIENT_SESSION
|
||||
|
||||
context: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_method: READABLE_STRING_8
|
||||
@@ -32,14 +41,23 @@ feature -- Access
|
||||
|
||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
|
||||
feature -- Execution
|
||||
feature {HTTP_CLIENT_SESSION} -- Execution
|
||||
|
||||
import (ctx: HTTP_CLIENT_REQUEST_CONTEXT)
|
||||
local
|
||||
l_headers: like headers
|
||||
do
|
||||
headers.fill (ctx.headers)
|
||||
l_headers := headers
|
||||
across
|
||||
ctx.headers as ctx_headers
|
||||
loop
|
||||
--| fill header from `ctx'
|
||||
--| and use `force' to overwrite the "session" value if any
|
||||
l_headers.force (ctx_headers.item, ctx_headers.key)
|
||||
end
|
||||
end
|
||||
|
||||
execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
execute: HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
@@ -41,8 +41,43 @@ feature -- Access
|
||||
raw_header: READABLE_STRING_8
|
||||
-- Raw http header of the response.
|
||||
|
||||
header (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
-- Header entry value related to `a_name'
|
||||
-- if multiple entries, just concatenate them using comma character
|
||||
--| See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
|
||||
--| Multiple message-header fields with the same field-name MAY be present in a message
|
||||
--| if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)].
|
||||
--| It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair,
|
||||
--| without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma.
|
||||
--| The order in which header fields with the same field-name are received is therefore significant
|
||||
--| to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of
|
||||
--| these field values when a message is forwarded.
|
||||
local
|
||||
s: detachable STRING_8
|
||||
k,v: READABLE_STRING_8
|
||||
do
|
||||
across
|
||||
headers as hds
|
||||
loop
|
||||
k := hds.item.key
|
||||
if k.same_string (a_name) then
|
||||
v := hds.item.value
|
||||
if s = Void then
|
||||
create s.make_from_string (v)
|
||||
else
|
||||
s.append_character (',')
|
||||
s.append (v)
|
||||
end
|
||||
end
|
||||
end
|
||||
Result := s
|
||||
end
|
||||
|
||||
headers: LIST [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||
-- Computed table of http headers of the response.
|
||||
--| We use a LIST since one might have multiple message-header fields with the same field-name
|
||||
--| Then the user can handle those case using default or custom concatenation
|
||||
--| (note: `header' is concatenating using comma)
|
||||
local
|
||||
tb: like internal_headers
|
||||
pos, l_start, l_end, n, c: INTEGER
|
||||
|
||||
@@ -20,9 +20,9 @@ create
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session)
|
||||
make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session; ctx: like context)
|
||||
do
|
||||
make_request (a_url, a_session)
|
||||
make_request (a_url, a_session, ctx)
|
||||
request_method := a_request_method
|
||||
end
|
||||
|
||||
@@ -34,7 +34,7 @@ feature -- Access
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
execute: HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
l_result: INTEGER
|
||||
l_curl_string: CURL_STRING
|
||||
@@ -45,7 +45,9 @@ feature -- Execution
|
||||
curl: CURL_EXTERNALS
|
||||
curl_easy: CURL_EASY_EXTERNALS
|
||||
curl_handle: POINTER
|
||||
ctx: like context
|
||||
do
|
||||
ctx := context
|
||||
curl := session.curl
|
||||
curl_easy := session.curl_easy
|
||||
|
||||
@@ -167,7 +169,15 @@ feature -- Execution
|
||||
p := curl.slist_append (p, curs.key + ": " + curs.item)
|
||||
end
|
||||
end
|
||||
|
||||
if ctx /= Void then
|
||||
if attached ctx.headers as l_headers_2 then
|
||||
across
|
||||
l_headers_2 as curs_2
|
||||
loop
|
||||
p := curl.slist_append (p, curs_2.key + ": " + curs_2.item)
|
||||
end
|
||||
end
|
||||
end
|
||||
p := curl.slist_append (p, "Expect:")
|
||||
curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
|
||||
|
||||
|
||||
@@ -27,16 +27,16 @@ feature -- Basic operation
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "GET", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "GET", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "HEAD", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "HEAD", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
post (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
@@ -54,7 +54,6 @@ feature -- Basic operation
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "POST", Current)
|
||||
ctx := a_ctx
|
||||
if data /= Void then
|
||||
if ctx = Void then
|
||||
@@ -68,7 +67,8 @@ feature -- Basic operation
|
||||
end
|
||||
ctx.set_upload_filename (fn)
|
||||
end
|
||||
Result := execute_request (req, ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "POST", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
put (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
@@ -76,7 +76,6 @@ feature -- Basic operation
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current)
|
||||
ctx := a_ctx
|
||||
if data /= Void then
|
||||
if ctx = Void then
|
||||
@@ -84,7 +83,8 @@ feature -- Basic operation
|
||||
end
|
||||
ctx.set_upload_data (data)
|
||||
end
|
||||
Result := execute_request (req, ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
put_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
@@ -92,7 +92,6 @@ feature -- Basic operation
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current)
|
||||
ctx := a_ctx
|
||||
if fn /= Void then
|
||||
if ctx = Void then
|
||||
@@ -100,25 +99,16 @@ feature -- Basic operation
|
||||
end
|
||||
ctx.set_upload_filename (fn)
|
||||
end
|
||||
Result := execute_request (req, ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "DELETE", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
execute_request (req: HTTP_CLIENT_REQUEST; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
do
|
||||
if ctx /= Void then
|
||||
req.import (ctx)
|
||||
end
|
||||
Result := req.execute (ctx)
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "DELETE", Current, ctx)
|
||||
Result := req.execute
|
||||
end
|
||||
|
||||
feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation
|
||||
|
||||
@@ -196,13 +196,13 @@ feature -- Content related header
|
||||
put_transfer_encoding_binary
|
||||
-- Put "Transfer-Encoding: binary" header
|
||||
do
|
||||
put_transfer_encoding ("binary")
|
||||
put_transfer_encoding (str_binary)
|
||||
end
|
||||
|
||||
put_transfer_encoding_chunked
|
||||
-- Put "Transfer-Encoding: chunked" header
|
||||
do
|
||||
put_transfer_encoding ("chunked")
|
||||
put_transfer_encoding (str_chunked)
|
||||
end
|
||||
|
||||
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
||||
@@ -354,6 +354,35 @@ feature -- Cookie
|
||||
|
||||
feature -- Status report
|
||||
|
||||
header_named_value (a_name: READABLE_STRING_8): detachable STRING_8
|
||||
-- Has header item for `n'?
|
||||
require
|
||||
has_header: has_header_named (a_name)
|
||||
local
|
||||
c: like headers.new_cursor
|
||||
n: INTEGER
|
||||
l_line: READABLE_STRING_8
|
||||
do
|
||||
from
|
||||
n := a_name.count
|
||||
c := headers.new_cursor
|
||||
until
|
||||
c.after or Result /= Void
|
||||
loop
|
||||
l_line := c.item
|
||||
if l_line.starts_with (a_name) then
|
||||
if l_line.valid_index (n + 1) then
|
||||
if l_line [n + 1] = ':' then
|
||||
Result := l_line.substring (n + 2, l_line.count)
|
||||
Result.left_adjust
|
||||
Result.right_adjust
|
||||
end
|
||||
end
|
||||
end
|
||||
c.forth
|
||||
end
|
||||
end
|
||||
|
||||
has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
||||
-- Has header item for `n'?
|
||||
local
|
||||
@@ -378,11 +407,26 @@ feature -- Status report
|
||||
end
|
||||
|
||||
has_content_length: BOOLEAN
|
||||
-- Has header "content_length"
|
||||
-- Has header "Content-Length"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length)
|
||||
end
|
||||
|
||||
has_content_type: BOOLEAN
|
||||
-- Has header "Content-Type"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_type)
|
||||
end
|
||||
|
||||
has_transfer_encoding_chunked: BOOLEAN
|
||||
-- Has "Transfer-Encoding: chunked" header
|
||||
do
|
||||
if has_header_named ({HTTP_HEADER_NAMES}.header_transfer_encoding) then
|
||||
Result := attached header_named_value ({HTTP_HEADER_NAMES}.header_transfer_encoding) as v and then v.same_string (str_chunked)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Implementation: Header
|
||||
|
||||
force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8)
|
||||
@@ -456,6 +500,9 @@ feature {NONE} -- Implementation
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
str_binary: STRING = "binary"
|
||||
str_chunked: STRING = "chunked"
|
||||
|
||||
colon_space: STRING = ": "
|
||||
semi_colon_space: STRING = "; "
|
||||
|
||||
|
||||
@@ -11,7 +11,11 @@ inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
create
|
||||
make
|
||||
make,
|
||||
make_with_body
|
||||
|
||||
convert
|
||||
make_with_body ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8})
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
@@ -21,6 +25,12 @@ feature {NONE} -- Initialization
|
||||
create header.make
|
||||
end
|
||||
|
||||
make_with_body (a_body: READABLE_STRING_8)
|
||||
do
|
||||
make
|
||||
body := a_body
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
status_code: INTEGER
|
||||
@@ -34,10 +44,24 @@ feature -- Header
|
||||
feature -- Output
|
||||
|
||||
send_to (res: WSF_RESPONSE)
|
||||
local
|
||||
b: like body
|
||||
h: like header
|
||||
do
|
||||
h := header
|
||||
b := body
|
||||
res.set_status_code (status_code)
|
||||
res.write_header_text (header.string)
|
||||
if attached body as b then
|
||||
|
||||
if b /= Void then
|
||||
if not h.has_content_length then
|
||||
h.put_content_length (b.count)
|
||||
end
|
||||
if not h.has_content_type then
|
||||
h.put_content_type_text_plain
|
||||
end
|
||||
end
|
||||
res.write_header_text (h.string)
|
||||
if b /= Void then
|
||||
res.write_string (b)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,19 +26,22 @@ convert
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_from_wgi (r: WGI_REQUEST)
|
||||
local
|
||||
tb: like meta_variables_table
|
||||
do
|
||||
wgi_request := r
|
||||
if attached r.meta_variables as l_vars then
|
||||
create meta_variables_table.make (l_vars.count)
|
||||
create tb.make (l_vars.count)
|
||||
across
|
||||
l_vars as c
|
||||
loop
|
||||
meta_variables_table.force (new_string_value (c.key, c.item), c.item)
|
||||
tb.force (new_string_value (c.key, c.item), c.key)
|
||||
end
|
||||
else
|
||||
create meta_variables_table.make (0)
|
||||
create tb.make (0)
|
||||
end
|
||||
meta_variables := meta_variables_table
|
||||
meta_variables_table := tb
|
||||
meta_variables := tb
|
||||
create error_handler.make
|
||||
create uploaded_files.make (0)
|
||||
raw_post_data_recorded := True
|
||||
|
||||
Reference in New Issue
Block a user