<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -120,6 +120,7 @@ Let's move on, creating a note using &lt;a href=&quot;http://tools.ietf.org/html/rfc2616
     $ curl -i -XPOST -d'{&quot;title&quot;:&quot;projects&quot;}' http://localhost:9292/notes&lt;br/&gt;
     HTTP/1.1 201 Created&lt;br/&gt;
     Cache-Control: no-cache&lt;br/&gt;
+    Location: http://localhost:9292/notes/0dda06f0-b134-012b-a2d8-0017f2c62348&lt;br/&gt;
     Content-Type: application/json&lt;br/&gt;
     Content-Length: 159&lt;br/&gt;&lt;br/&gt;
 
@@ -139,6 +140,7 @@ so that we can specify its location:
     $ curl -i -XPUT -d'{&quot;title&quot;:&quot;reminders&quot;}' http://localhost:9292/notes/abc&lt;br/&gt;
     HTTP/1.1 201 Created&lt;br/&gt;
     Cache-Control: no-cache&lt;br/&gt;
+    Location: http://localhost:9292/notes/abc&lt;br/&gt;
     Content-Type: application/json&lt;br/&gt;
     Content-Length: 126&lt;br/&gt;&lt;br/&gt;
 </diff>
      <filename>doc/curl.html</filename>
    </modified>
    <modified>
      <diff>@@ -168,5 +168,10 @@ module CloudKit
     def flash
       session[CLOUDKIT_FLASH] ||= CloudKit::FlashSession.new
     end
+
+    # Return the host and scheme
+    def domain_root
+      &quot;#{scheme}://#{@env['HTTP_HOST']}&quot;
+    end
   end
 end</diff>
      <filename>lib/cloudkit/request.rb</filename>
    </modified>
    <modified>
      <diff>@@ -68,18 +68,22 @@ module CloudKit
       if tunnel_methods.include?(request['_method'].try(:upcase))
         return send(request['_method'].downcase, request)
       end
-      @store.post(
+      response = @store.post(
         request.uri,
         {:json =&gt; request.json}.filter_merge!(
-          :remote_user =&gt; request.current_user)).to_rack
+          :remote_user =&gt; request.current_user))
+      update_location_header(request, response)
+      response.to_rack
     end
 
     def put(request)
-      @store.put(
+      response = @store.put(
         request.uri,
         {:json =&gt; request.json}.filter_merge!(
           :remote_user =&gt; request.current_user,
-          :etag        =&gt; request.if_match)).to_rack
+          :etag        =&gt; request.if_match))
+      update_location_header(request, response)
+      response.to_rack
     end
 
     def delete(request)
@@ -114,21 +118,26 @@ module CloudKit
     end
 
     def versions_link_header(request)
-      base_url = &quot;#{request.scheme}://#{request.env['HTTP_HOST']}#{request.path_info}&quot;
+      base_url = &quot;#{request.domain_root}#{request.path_info}&quot;
       &quot;&lt;#{base_url}/versions&gt;; rel=\&quot;http://joncrosby.me/cloudkit/1.0/rel/versions\&quot;&quot;
     end
 
     def resolved_link_header(request)
-      base_url = &quot;#{request.scheme}://#{request.env['HTTP_HOST']}#{request.path_info}&quot;
+      base_url = &quot;#{request.domain_root}#{request.path_info}&quot;
       &quot;&lt;#{base_url}/_resolved&gt;; rel=\&quot;http://joncrosby.me/cloudkit/1.0/rel/resolved\&quot;&quot;
     end
 
     def index_link_header(request)
       index_path = request.path_info.sub(/\/_resolved(\/)*$/, '')
-      base_url = &quot;#{request.scheme}://#{request.env['HTTP_HOST']}#{index_path}&quot;
+      base_url = &quot;#{request.domain_root}#{index_path}&quot;
       &quot;&lt;#{base_url}&gt;; rel=\&quot;index\&quot;&quot;
     end
 
+    def update_location_header(request, response)
+      return unless response['Location']
+      response['Location'] = &quot;#{request.domain_root}#{response['Location']}&quot;
+    end
+
     def auth_missing?(request)
       request.current_user == nil
     end</diff>
      <filename>lib/cloudkit/service.rb</filename>
    </modified>
    <modified>
      <diff>@@ -118,7 +118,7 @@ module CloudKit
 
       resource.delete
       archived_resource = resource.previous_version
-      return json_meta_response(200, archived_resource.uri.string, archived_resource.etag, resource.last_modified)
+      return json_meta_response(archived_resource.uri.string, archived_resource.etag, resource.last_modified)
     end
 
     # Build a response containing the allowed methods for a given URI.
@@ -277,7 +277,7 @@ module CloudKit
     def create_resource(uri, options)
       JSON.parse(options[:json]) rescue (return status_422)
       resource = CloudKit::Resource.create(uri, options[:json], options[:remote_user])
-      json_meta_response(201, resource.uri.string, resource.etag, resource.last_modified)
+      json_create_response(resource.uri.string, resource.etag, resource.last_modified)
     end
 
     # Update the resource at the specified URI. Requires the :etag option.
@@ -289,7 +289,7 @@ module CloudKit
       return etag_required unless options[:etag]
       return status_412    unless options[:etag] == resource.etag
       resource.update(options[:json])
-      return json_meta_response(200, uri.string, resource.etag, resource.last_modified)
+      return json_meta_response(uri.string, resource.etag, resource.last_modified)
     end
 
     # Bundle a collection of results as a list of URIs for the response.</diff>
      <filename>lib/cloudkit/store.rb</filename>
    </modified>
    <modified>
      <diff>@@ -46,21 +46,32 @@ module CloudKit::ResponseHelpers
 
   def response(status, content='', etag=nil, last_modified=nil, options={})
     cache_control = options[:cache] == false ? 'no-cache' : 'proxy-revalidate'
-    headers = {
+    etag = &quot;\&quot;#{etag}\&quot;&quot; if etag
+    headers = {}.filter_merge!(
       'Content-Type'  =&gt; 'application/json',
-      'Cache-Control' =&gt;  cache_control}
-    headers.merge!('ETag' =&gt; &quot;\&quot;#{etag}\&quot;&quot;) if etag
-    headers.merge!('Last-Modified' =&gt; last_modified) if last_modified
+      'Cache-Control' =&gt;  cache_control,
+      'Last-Modified' =&gt; last_modified,
+      'Location'      =&gt; options[:location],
+      'ETag'          =&gt; etag)
     CloudKit::Response.new(status, headers, content)
   end
 
-  def json_meta_response(status, uri, etag, last_modified)
-    json = JSON.generate(
+  def json_meta_response(uri, etag, last_modified)
+    json = json_metadata(uri, etag, last_modified)
+    response(200, json, nil, nil, :cache =&gt; false)
+  end
+
+  def json_create_response(uri, etag, last_modified)
+    json = json_metadata(uri, etag, last_modified)
+    response(201, json, nil, nil, {:cache =&gt; false, :location =&gt; uri})
+  end
+
+  def json_metadata(uri, etag, last_modified)
+    JSON.generate(
       :ok            =&gt; true,
       :uri           =&gt; uri,
       :etag          =&gt; etag,
       :last_modified =&gt; last_modified)
-    response(status, json, nil, nil, :cache =&gt; false)
   end
 
   def json_error(message)</diff>
      <filename>lib/cloudkit/store/response_helpers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -182,4 +182,10 @@ describe &quot;A Request&quot; do
     request.last_path_element.should == 'def'
   end
 
+  it &quot;should know its domain root&quot; do
+    request = CloudKit::Request.new(Rack::MockRequest.env_for(
+      '/', 'HTTP_HOST' =&gt; 'example.com'))
+    request.domain_root.should == &quot;http://example.com&quot;
+  end
+
 end</diff>
      <filename>spec/request_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -570,7 +570,7 @@ describe &quot;A CloudKit::Service&quot; do
       before(:each) do
         json = JSON.generate(:this =&gt; 'that')
         @response = @request.post(
-          '/items', {:input =&gt; json}.merge(VALID_TEST_AUTH))
+          '/items', {:input =&gt; json, 'HTTP_HOST' =&gt; 'example.org'}.merge(VALID_TEST_AUTH))
         @body = JSON.parse(@response.body)
       end
 
@@ -600,6 +600,10 @@ describe &quot;A CloudKit::Service&quot; do
         @response['Last-Modified'].should be_nil
       end
 
+      it &quot;should return a Location header&quot; do
+        @response['Location'].should match(/http:\/\/example.org#{@body['uri']}/)
+      end
+
       it &quot;should return a 422 if parsing fails&quot; do
         response = @request.post('/items', {:input =&gt; 'fail'}.merge(VALID_TEST_AUTH))
         response.status.should == 422
@@ -607,7 +611,7 @@ describe &quot;A CloudKit::Service&quot; do
 
     end
 
-    describe &quot;on PUT /:collection/:id&quot; do 
+    describe &quot;on PUT /:collection/:id&quot; do
 
       before(:each) do
         json = JSON.generate(:this =&gt; 'that')
@@ -626,11 +630,15 @@ describe &quot;A CloudKit::Service&quot; do
       it &quot;should create a document if it does not already exist&quot; do
         json = JSON.generate(:this =&gt; 'thing')
         response = @request.put(
-          '/items/xyz', {:input =&gt; json}.merge(VALID_TEST_AUTH))
+          '/items/xyz', {
+            :input      =&gt; json,
+            'HTTP_HOST' =&gt; 'example.org'}.merge(VALID_TEST_AUTH))
         response.status.should == 201
         result = @request.get('/items/xyz', VALID_TEST_AUTH)
         result.status.should == 200
-        JSON.parse(result.body)['this'].should == 'thing'
+        parsed_json = JSON.parse(result.body)['this']
+        parsed_json.should == 'thing'
+        response['Location'].should match(/http:\/\/example.org#{parsed_json['uri']}/)
       end
 
       it &quot;should not create new resources using deleted resource URIs&quot; do</diff>
      <filename>spec/service_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>1fbd6d2e40cd71f895f5ac3fd746e1fa27d66940</id>
    </parent>
  </parents>
  <author>
    <name>Jon Crosby</name>
    <email>jon@joncrosby.me</email>
  </author>
  <url>http://github.com/jcrosby/cloudkit/commit/ced6a2631f83696c7003024171a4a86deff881a2</url>
  <id>ced6a2631f83696c7003024171a4a86deff881a2</id>
  <committed-date>2009-05-02T12:51:16-07:00</committed-date>
  <authored-date>2009-05-02T12:51:16-07:00</authored-date>
  <message>Add Location header for 201s</message>
  <tree>9e4452ce3fb98094222a97c8d1eed53b4da13439</tree>
  <committer>
    <name>Jon Crosby</name>
    <email>jon@joncrosby.me</email>
  </committer>
</commit>
