how to make redirect in webrick/ruby? - ruby

How to make Redirect in WEBRICK Ruby, can the simplest example with the syntax?
In this example
require 'webrick'
class MyServlet < WEBrick::HTTPServlet::AbstractServlet
def do_GET (request, response)
result = ""
case request.path
when "/redirect_test"
puts("not yet working")
when "/test"
result = " arg"
when "/"
else
result = " error"
end
response.body = "main"+result
end
end
server = WEBrick::HTTPServer.new(:Port => 1234)
server.mount "/", MyServlet
server.start

Related

Ruby base_auth with net/http - undefined method `user' for String

I've got pure Ruby app where I want to create request to external API. To do so I'm using standard Ruby Net::HTTP like below:
require 'net/http'
require 'uri'
class Api
BASE_URI = 'https://staging.test.com'
WORKFLOW = 'tests'
QUIZ_PATH = "/v3/accounts/workflows/#{WORKFLOW}/conversations"
def initialize(payload:)
#payload = payload
end
def post_quiz
handle_response(Net::HTTP.post_form("#{BASE_URI}#{QUIZ_PATH}", options))
end
attr_reader :payload
private
def options
{
basic_auth: basic_auth,
body: payload.to_json,
headers: headers
}
end
def basic_auth
{
username: Settings.ln_username,
password: Settings.ln_password
}
end
def headers
{
'User-Agent' => 'Mozilla/5.0',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Type' => 'application/json'
}
end
def handle_response(response)
return response.body if response.success?
end
end
But instead of response I'm getting an error:
NoMethodError: undefined method `user' for #String:0x00007f80eef9e6f8
Did you mean? super
/Users/usr/.rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/net/http.rb:527:in `post_form'
I don't have any user there, what is it?
Net::HTTP.post_form is used to send FormData pairs - its not what you want to send JSON and it doesn't even allow you to send headers (You're actually putting them in the request body!).
If you want to send a POST request with HTTP Basic auth and custom headers and JSON body you need to create the request object manually:
require 'net/http'
require 'uri'
class Api
BASE_URI = 'https://staging.test.com'
WORKFLOW = 'tests'
QUIZ_PATH = "/v3/accounts/workflows/#{WORKFLOW}/conversations"
attr_reader :payload
def initialize(payload:)
#payload = payload
end
def post_quiz
url = URI.join(BASE_URI, QUIZ_PATH)
request = Net::HTTP::Post.new(url, headers)
request.basic_auth = Settings.ln_username, Settings.ln_password
request.body = #payload.to_json
# open a connection to the server
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
http.request(request)
end
handle_response(response)
end
private
def headers
{
'User-Agent' => 'Mozilla/5.0',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Type' => 'application/json'
}
end
# How to respond from an API client is a whole topic in itself but a tuple or hash might
# be a better choice as it lets consumers decide what to do with the response and handle stuff like logging
# errors
def handle_response(response)
# Net::HTTP doesn't have a success? method - you're confusing it with HTTParty
case response
when Net::HTTPSuccess, Net::HTTPCreated
response.body
else
false
end
end
end
Here is the source code that raises the error:
def HTTP.post_form(url, params)
req = Post.new(url)
req.form_data = params
>> req.basic_auth url.user, url.password if url.user
start(url.hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.request(req)
}
end
From the docs:
post_form(url, params)
Posts HTML form data to the specified URI object. The form data must be provided as a Hash mapping from String to String.
That means Net::HTTP.post_form(URI("#{BASE_URI}#{QUIZ_PATH}"), options) fixes it. You are currently sending a string as url instead of a URI.

How to test a ruby function which makes a HTTP POST call with rspec?

How can i mock an API, giving fake credentials (username and password) to the method with rspec and with/out any other gem?
Here is the function i want to test:
require 'rubygems'
require 'http'
require 'json'
require_relative './read_file'
def post_gists(user_name, password, file_name)
file_as_string = file_to_string(file_name)
file_name = File.basename(file_name)
obj = {
description: "",
public: true,
files: {
file_name.to_sym => {
content: file_as_string
}
}
}
response = HTTP.basic_auth(user: user_name, pass: password)
.headers(accept: "application/json")
.post('https://api.github.com/gists', json: obj)
if response.code == 201
body_hash = JSON.parse(response.body.to_s)
message = "The file #{file_name} was uploaded correctly at #{body_hash["html_url"]}"
elsif response.code == 401
message = "There was a problem with the credentials of the account"
else
message = "There was a problem uploading the file #{file_name}"
end
message
end

Display content on PM::WebScreen from BubbleWrap response

class WorkoutScreen < PM::WebScreen
title "Workouts"
def content
#response
end
def on_load
set_nav_bar_button :left, title: "Menu", action: :nav_left_button
end
def load_started
#response = ''
BubbleWrap::HTTP.get("my_url", {async: false, :headers => { "User-Agent" => "value"}}) do |response|
#response = response.body.to_str
end
end
def nav_left_button
app_delegate.menu.show(:left)
end
end
I need to send HTTP request with specific header, but content always nil . I have checked response by sniffer - everything is Ok.
If I do this way
class WorkoutScreen < PM::WebScreen
title "Workouts"
def content
#response = ''
BubbleWrap::HTTP.get("my_url", {async: false, :headers => { "User-Agent" => "value"}}) do |response|
#response = response.body.to_str
end
#response
end
I see
eb_screen_module.rb:50:in `set_content:': Is a directory - read() failed (Errno::EISDIR)
exception
NSUserDefaults.standardUserDefaults.registerDefaults({UserAgent: "value"})
Found solution myself

Faraday get access to the request parameters

Struggling a bit with faraday. I would like to know what I actually send to the server. I get the response body, but not access the request body. I found that there is a request.env method, but I can't get access to the body there somehow.
How would that work?
conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
data = conn.post do |req|
req.url '/nigiri'
req.headers['Content-Type'] = 'application/json'
req.body = '{ "name": "Unagi" }'
end
# how do I get access to the request body here?
What I tried doing was this:
[4] pry(main)> request.env.request
=> #<struct Faraday::RequestOptions
params_encoder=nil,
proxy=nil,
bind=nil,
timeout=nil,
open_timeout=nil,
boundary=nil,
oauth=nil>
But I have no access to the body. Any ideas?
Thanks!
You could try implementing a middleware just for this purpose. Just to give you a quick idea on what you can do to achieve this (there might be an easier way but I don't really know, I suppose because you specify the request body there's no real need to capture this as you should already have this available).
require 'faraday'
class RequestBody < Faraday::Middleware
def call(env)
request_body = env.body
#app.call(env).on_complete do |response|
response[:request_body] = request_body
end
end
end
conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
faraday.use RequestBody
faraday.adapter Faraday.default_adapter
end
data = conn.post do |req|
req.url '/nigiri'
req.headers['Content-Type'] = 'application/json'
req.headers['foo'] = 'bar'
req.body = '{ "name": "Unagi" }'
end
# 2.2.2 > data.env[:request_body]
# => "{ \"name\": \"Unagi\" }"
# 2.2.2 > data.env.request_headers
# => {"User-Agent"=>"Faraday v0.9.2", "Content-Type"=>"application/json", "foo"=>"bar"}
# 2.2.2 > data.body
# => "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>301 Moved Permanently</title>\n</head><body>\n<h1>Moved Permanently</h1>\n<p>The document has moved here.</p>\n<hr>\n<address>Apache/2.4.10 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4 PHP/5.4.32 Server at sushi.com Port 80</address>\n</body></html>\n"

Error on a Sinatra's middleware

In my Sinatra app, I've created the following middleware to ensure the incoming request contains the parameter "token" in the query string
class CheckMandatoryParams
def initialize(app)
#app = app
end
def call(env)
# Get token from query string
h = Hash[*env["QUERY_STRING"].split('&').map {|s| s.split('=')}.flatten]
token = h["token"]
# Do not authorize request unless both parameters are not null
if token.nil? then
Log.instance.error("CheckMandatoryParams - token not provided")
[401, {"Content-Type" => "text/plain", "Content-Length" => body.length.to_s}, ["Unauthorized"]]
else
Log.instance.debug("CheckMandatoryParams - token provided")
#app.call(env)
end
end
end
In the case the params exists, the next app is calls and everything goes fine.
In the case the params is not in the query string, the response is not sent, I receive a huge html file indicating an error at the line ' [401, {"Content-Type" => "text/plain", "Content-Length" => body.length.to_s}, ["Unauthorized"]]' but I cannot figure out what is wrong.
Any idea?
UPDATE
This is working better like that :)
body = "Unauthorized"
[401, {"Content-Type" => "text/plain", "Content-Length" => body.length.to_s}, [body]]
I did not manage to retrieve the param with the following code though:
request = Rack::Request.new(env)
token = request.params["token"]
It looks like the "body" variable may be undefined. One possible way to rewrite your code would be as follows:
class CheckMandatoryParams
def initialize(app)
#app = app
end
def call(env)
request = Rack::Request.new(env)
token = request.params["token"]
if token.nil?
[401, {"Content-Type" => "text/plain", "Content-Length" => request.body.length.to_s}, ["Unauthorized"]]
else
#app.call(env)
end
end
end

Resources