Merge pull request #83 from 5apps/feature/message_body_contents
Send message body contents for 401, 404, 409 and 412 responses
This commit is contained in:
		
						commit
						a9e4b93cdc
					
				@ -24,12 +24,14 @@ module RemoteStorage
 | 
				
			|||||||
        return true if ["GET", "HEAD"].include?(request_method) && !listing
 | 
					        return true if ["GET", "HEAD"].include?(request_method) && !listing
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      server.halt 401, "Unauthorized" if token.empty?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      authorizations = redis.smembers("authorizations:#{user}:#{token}")
 | 
					      authorizations = redis.smembers("authorizations:#{user}:#{token}")
 | 
				
			||||||
      permission = directory_permission(authorizations, directory)
 | 
					      permission = directory_permission(authorizations, directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      server.halt 401 unless permission
 | 
					      server.halt 401, "Unauthorized" unless permission
 | 
				
			||||||
      if ["PUT", "DELETE"].include? request_method
 | 
					      if ["PUT", "DELETE"].include? request_method
 | 
				
			||||||
        server.halt 401 unless permission == "rw"
 | 
					        server.halt 401, "Unauthorized" unless permission == "rw"
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -55,7 +57,7 @@ module RemoteStorage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return res.body
 | 
					      return res.body
 | 
				
			||||||
    rescue RestClient::ResourceNotFound
 | 
					    rescue RestClient::ResourceNotFound
 | 
				
			||||||
      server.halt 404
 | 
					      server.halt 404, "Not Found"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_head_directory_listing(user, directory)
 | 
					    def get_head_directory_listing(user, directory)
 | 
				
			||||||
@ -131,16 +133,16 @@ module RemoteStorage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def put_data(user, directory, key, data, content_type)
 | 
					    def put_data(user, directory, key, data, content_type)
 | 
				
			||||||
      server.halt 400 if server.env["HTTP_CONTENT_RANGE"]
 | 
					      server.halt 400 if server.env["HTTP_CONTENT_RANGE"]
 | 
				
			||||||
      server.halt 409 if has_name_collision?(user, directory, key)
 | 
					      server.halt 409, "Conflict" if has_name_collision?(user, directory, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      existing_metadata = redis.hgetall redis_metadata_object_key(user, directory, key)
 | 
					      existing_metadata = redis.hgetall redis_metadata_object_key(user, directory, key)
 | 
				
			||||||
      url = url_for_key(user, directory, key)
 | 
					      url = url_for_key(user, directory, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if required_match = server.env["HTTP_IF_MATCH"]
 | 
					      if required_match = server.env["HTTP_IF_MATCH"]
 | 
				
			||||||
        server.halt 412 unless required_match == %Q("#{existing_metadata["e"]}")
 | 
					        server.halt 412, "Precondition Failed" unless required_match == %Q("#{existing_metadata["e"]}")
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
      if server.env["HTTP_IF_NONE_MATCH"] == "*"
 | 
					      if server.env["HTTP_IF_NONE_MATCH"] == "*"
 | 
				
			||||||
        server.halt 412 unless existing_metadata.empty?
 | 
					        server.halt 412, "Precondition Failed" unless existing_metadata.empty?
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      res = do_put_request(url, data, content_type)
 | 
					      res = do_put_request(url, data, content_type)
 | 
				
			||||||
@ -176,7 +178,7 @@ module RemoteStorage
 | 
				
			|||||||
      existing_metadata = redis.hgetall "rs:m:#{user}:#{directory}/#{key}"
 | 
					      existing_metadata = redis.hgetall "rs:m:#{user}:#{directory}/#{key}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if required_match = server.env["HTTP_IF_MATCH"]
 | 
					      if required_match = server.env["HTTP_IF_MATCH"]
 | 
				
			||||||
        server.halt 412 unless required_match == %Q("#{existing_metadata["e"]}")
 | 
					        server.halt 412, "Precondition Failed" unless required_match == %Q("#{existing_metadata["e"]}")
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      do_delete_request(url)
 | 
					      do_delete_request(url)
 | 
				
			||||||
@ -185,7 +187,7 @@ module RemoteStorage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      server.halt 200
 | 
					      server.halt 200
 | 
				
			||||||
    rescue RestClient::ResourceNotFound
 | 
					    rescue RestClient::ResourceNotFound
 | 
				
			||||||
      server.halt 404
 | 
					      server.halt 404, "Not Found"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
 | 
				
			|||||||
@ -134,6 +134,7 @@ describe "App" do
 | 
				
			|||||||
          end
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          last_response.status.must_equal 409
 | 
					          last_response.status.must_equal 409
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Conflict"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          metadata = redis.hgetall "rs:m:phil:food"
 | 
					          metadata = redis.hgetall "rs:m:phil:food"
 | 
				
			||||||
          metadata.must_be_empty
 | 
					          metadata.must_be_empty
 | 
				
			||||||
@ -164,7 +165,82 @@ describe "App" do
 | 
				
			|||||||
          last_response.status.must_equal 400
 | 
					          last_response.status.must_equal 400
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "If-Match header" do
 | 
				
			||||||
 | 
					        before do
 | 
				
			||||||
 | 
					          put_stub = OpenStruct.new(headers: {
 | 
				
			||||||
 | 
					            etag: "oldetag",
 | 
				
			||||||
 | 
					            last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          RestClient.stub :put, put_stub do
 | 
				
			||||||
 | 
					            put "/phil/food/aguacate", "si"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it "allows the request if the header matches the current ETag" do
 | 
				
			||||||
 | 
					          header "If-Match", "\"oldetag\""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          put_stub = OpenStruct.new(headers: {
 | 
				
			||||||
 | 
					            etag: "newetag",
 | 
				
			||||||
 | 
					            last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          RestClient.stub :put, put_stub do
 | 
				
			||||||
 | 
					            put "/phil/food/aguacate", "aye"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 200
 | 
				
			||||||
 | 
					          last_response.headers["Etag"].must_equal "\"newetag\""
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it "fails the request if the header does not match the current ETag" do
 | 
				
			||||||
 | 
					          header "If-Match", "someotheretag"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          put "/phil/food/aguacate", "aye"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 412
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Precondition Failed"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "If-None-Match header set to '*'" do
 | 
				
			||||||
 | 
					        it "succeeds when the document doesn't exist yet" do
 | 
				
			||||||
 | 
					          put_stub = OpenStruct.new(headers: {
 | 
				
			||||||
 | 
					            etag: "someetag",
 | 
				
			||||||
 | 
					            last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          header "If-None-Match", "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          RestClient.stub :put, put_stub do
 | 
				
			||||||
 | 
					            put "/phil/food/aguacate", "si"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 200
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it "fails the request if the document already exsits" do
 | 
				
			||||||
 | 
					          put_stub = OpenStruct.new(headers: {
 | 
				
			||||||
 | 
					            etag: "someetag",
 | 
				
			||||||
 | 
					            last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          RestClient.stub :put, put_stub do
 | 
				
			||||||
 | 
					            put "/phil/food/aguacate", "si"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          header "If-None-Match", "*"
 | 
				
			||||||
 | 
					          RestClient.stub :put, put_stub do
 | 
				
			||||||
 | 
					            put "/phil/food/aguacate", "si"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 412
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Precondition Failed"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe "DELETE requests" do
 | 
					  describe "DELETE requests" do
 | 
				
			||||||
@ -173,6 +249,29 @@ describe "App" do
 | 
				
			|||||||
      purge_redis
 | 
					      purge_redis
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context "not authorized" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "with no token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          delete "/phil/food/aguacate"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Unauthorized"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "with wrong token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          header "Authorization", "Bearer wrongtoken"
 | 
				
			||||||
 | 
					          delete "/phil/food/aguacate"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Unauthorized"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context "authorized" do
 | 
					    context "authorized" do
 | 
				
			||||||
      before do
 | 
					      before do
 | 
				
			||||||
        redis.sadd "authorizations:phil:amarillo", [":rw"]
 | 
					        redis.sadd "authorizations:phil:amarillo", [":rw"]
 | 
				
			||||||
@ -239,6 +338,37 @@ describe "App" do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        redis.smembers("rs:m:phil:/:items").must_be_empty
 | 
					        redis.smembers("rs:m:phil:/:items").must_be_empty
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it "returns a 404 when item doesn't exist" do
 | 
				
			||||||
 | 
					        raises_exception = ->(url, headers) { raise RestClient::ResourceNotFound.new }
 | 
				
			||||||
 | 
					        RestClient.stub :delete, raises_exception do
 | 
				
			||||||
 | 
					          delete "/phil/food/steak"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        last_response.status.must_equal 404
 | 
				
			||||||
 | 
					        last_response.body.must_equal "Not Found"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "If-Match header" do
 | 
				
			||||||
 | 
					        it "succeeds when the header matches the current ETag" do
 | 
				
			||||||
 | 
					          header "If-Match", "\"bla\""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          RestClient.stub :delete, "" do
 | 
				
			||||||
 | 
					            delete "/phil/food/aguacate"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 200
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it "fails the request if it does not match the current ETag" do
 | 
				
			||||||
 | 
					          header "If-Match", "someotheretag"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          delete "/phil/food/aguacate"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 412
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Precondition Failed"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -248,6 +378,29 @@ describe "App" do
 | 
				
			|||||||
      purge_redis
 | 
					      purge_redis
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context "not authorized" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "without token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          get "/phil/food/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Unauthorized"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "with wrong token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          header "Authorization", "Bearer wrongtoken"
 | 
				
			||||||
 | 
					          get "/phil/food/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Unauthorized"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context "authorized" do
 | 
					    context "authorized" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      before do
 | 
					      before do
 | 
				
			||||||
@ -266,6 +419,20 @@ describe "App" do
 | 
				
			|||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "data" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it "returns a 404 when data doesn't exist" do
 | 
				
			||||||
 | 
					          raises_exception = ->(url, headers) { raise RestClient::ResourceNotFound.new }
 | 
				
			||||||
 | 
					          RestClient.stub :get, raises_exception do
 | 
				
			||||||
 | 
					            get "/phil/food/steak"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 404
 | 
				
			||||||
 | 
					          last_response.body.must_equal "Not Found"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      describe "directory listings" do
 | 
					      describe "directory listings" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        it "has an ETag in the header" do
 | 
					        it "has an ETag in the header" do
 | 
				
			||||||
@ -317,5 +484,58 @@ describe "App" do
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe "HEAD requests" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    before do
 | 
				
			||||||
 | 
					      purge_redis
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context "not authorized" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "without token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          head "/phil/food/camarones"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_be_empty
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "with wrong token" do
 | 
				
			||||||
 | 
					        it "says it's not authorized" do
 | 
				
			||||||
 | 
					          header "Authorization", "Bearer wrongtoken"
 | 
				
			||||||
 | 
					          head "/phil/food/camarones"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 401
 | 
				
			||||||
 | 
					          last_response.body.must_be_empty
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context "authorized" do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      before do
 | 
				
			||||||
 | 
					        redis.sadd "authorizations:phil:amarillo", [":rw"]
 | 
				
			||||||
 | 
					        header "Authorization", "Bearer amarillo"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe "data" do
 | 
				
			||||||
 | 
					        it "returns a 404 when data doesn't exist" do
 | 
				
			||||||
 | 
					          raises_exception = ->(url, headers) { raise RestClient::ResourceNotFound.new }
 | 
				
			||||||
 | 
					          RestClient.stub :head, raises_exception do
 | 
				
			||||||
 | 
					            head "/phil/food/steak"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          last_response.status.must_equal 404
 | 
				
			||||||
 | 
					          last_response.body.must_be_empty
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user