how to code web/application server in ruby? - ruby

I need to
run ant remotelly
create/modify xml files for ant
pass back results from ant's execution
so I thought I am going to write a web/application server in ruby. But I do not know where to start.
The computer that will run ant is Win XP SP3 and there is no web server or anything else running.
I found this code but not sure which part to modify so I does what I want. Let's say I want to run "dir" command and send back to the browser result of that command.
require 'socket'
webserver = TCPServer.new('127.0.0.1', 7125)
while (session = webserver.accept)
session.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
request = session.gets
trimmedrequest = request.gsub(/GET\ \//, '').gsub(/\ HTTP.*/, '')
filename = trimmedrequest.chomp
if filename == ""
filename = "index.html"
end
begin
displayfile = File.open(filename, 'r')
content = displayfile.read()
session.print content
rescue Errno::ENOENT
session.print "File not found"
end
session.close
end

Ruby includes a Web server (WEBrick) so you don't actually need to use the code that you posted. Sinatra is designed specifically for writing very small Web applications - it lets you write a Web application in a few lines of code and automatically uses the provided Web server.

You can use ruby web server such as Rack, Webrick, mongrel, also you can use Ruby on Rails, Sinatra what else you want.
Of course you can write code from scratch, but it's not good idea to write whole by your own.

Related

Basic Ruby http server not displaying .jpg to localhost on win7?

This http script works just fine from my gnome-terminal on Ubuntu (and per Aleksey, on Mac), but on win7, a small square gets loaded in the chrome browser. What do I need to do to get the JPEG sent through local host so it displays in the win7 browser? Per Holger's comment, I need to address the content encoding, but everything I've tried so far makes no difference on win7 (and still loads fine in Ubuntu without any explicit content encoding). ?.
PS C:\Users\user_name\Ruby\http_test> ls
basic_http.rb
lolcat.jpg
PS C:\Users\user_name\Ruby\http_test> ruby basic_http.rb
# very basic http server
require 'socket'
def send_200(socket, content)
socket.puts "HTTP/1.1 200 OK\r\n\r\n#{content}" # <-- Correct? (Per Holger)
socket.close
end
server = TCPServer.new 2016
loop do
Thread.start(server.accept) do |client|
request = client.gets
if request.start_with?("GET")
url = request.split(" ")[1]
if url.start_with?("/images/")
file = url.sub("/images/", "")
picture = File.read(file) # <-- initially Aleksey pointed out
send_200(client, picture) # <-- a variable name mismatch here
else # pictures/picture... heh.
send_200(client, "hello!")
end
end
end
end
FWIW: Ruby 2.2, win7 & coding along with this demo.
You just have a typo in variable name.
You read file to pictures
pictures = File.read(file)
but you send it as picture
send_200(client, picture)
So you just need to edit variable name.
Maybe it would be a good idea to wrap request procession into begin block.
Thread.start(server.accept) do |client|
begin
...
rescue => ex
puts ex
end
end
This way you can see if something goes wrong.
To get the jpeg loaded into the browser on a win7 system, the File.read command needs to explicitly address the binary content encoding, e.g. File.binread("foo.bar") per:
https://ruby-doc.org/core-2.1.0/IO.html#method-c-binread
if url.start_with?("/images/")
file = url.sub("/images/", "")
picture = File.binread(file) # <-- Thank you Holger & Aleksey!!!
send_200(client, picture)
Thanks to Aleksey and Holger!

Open a local file with open-uri

I am doing data scraping with Ruby and Nokogiri. Is it possible to download and parse a local file in my computer?
I have:
require 'open-uri'
url = "file:///home/nav/Desktop/Scraping/scrap1.html"
It gives error as:
No such file or directory # rb_sysopen - file:\home/nav/Desktop/Scraping/scrap1.html
If you want to parse a local file with Nokogiri you can do it like this.
file = File.read('/home/nav/Desktop/Scraping/scrap1.html')
doc = Nokogiri::HTML(file)
When you open a local file in a browser, the URL in the address bar is displayed as:
file:///Users/7stud/Desktop/accounts.txt
But that doesn't mean you use that format in a Ruby script. Your Ruby script doesn't send the file name to a browser and then ask the browser to retrieve the file. Your Ruby script searches your file system directly.
The same is true for URLs: your Ruby script doesn't ask your browser to go retrieve a page from the internet, Ruby retrieves the page itself by sending a request using your system's network interface. After all, a browser and a Ruby program are both just computer programs. What your browser can do over a network, a Ruby program can do, too.
This works for me:
require 'open-uri'
text = open('./data.txt').read
puts text
You have to get your path right, though. The only reason I can think of to use open() is if you had an array of filenames and URLs mixed together. If that isn't your situation, see new2code's answer.
This is how I do it as according to the documentation.
f = File.open("//home/nav/Desktop/Scraping/scrap1.html")
doc = Nokogiri::HTML(f)
f.close
I would make use of Mechanize and save the file locally, then parse it with Nokogiri like so:
# Save the file
agent = Mechanize.new
agent.pluggable_parser.default = Mechanize::Download
current_url = 'http://www.example.com'
file = agent.get(current_url)
file.save!("#{Rails.root}/tmp/")
# Read the file
page = Nokogiri::HTML::Reader(File.open(file))
Hope that helps!

How can I execute Ruby code with WEBrick instead of dumping the code to my browser?

I'm facing a problem when I run my program in a browser with the WEBrick server. It shows me my code as written in the 2loop.rb file.
When I run ruby -run -e -httpd. -p 5000 at the command prompt, and load http://localhost:5000/2loop.rb in the browser, it shows the code from 2loop.rb instead of running it.
How can I execute the 2loop.rb program instead?
TL;DR
You're doing this to yourself by serving your current working directory as the root of your web server. You aren't actually running the code in your file; you're just telling WEBrick to serve any file you name in the URI. http://localhost:5000/2loop.rb will serve "2loop.rb" as text/html in your posted example.
Using un.rb
The flag you're using isn't actually "run." Instead, the -r flag actually loads a module, which in this case is the un.rb module. Using un.rb to start WEBrick is done like this:
$ ruby -run -e httpd . -p 5000
and starts a web server in the document root. In this case, the dot means to use the current working directory as the root. This is not really what you want to start code you've placed inside a Ruby file.
Running WEBrick Programmatically
Using some snippets from the WEBrick documentation, you will see that you can create a file named "2loop.rb" containing the following:
#!/usr/bin/env ruby
require 'webrick'
root = File.path '/tmp/public_html'
server = WEBrick::HTTPServer.new :Port => 5000, :DocumentRoot => root
trap 'INT' do server.shutdown end
server.start
This will serve files out of the /tmp/public_html directory on port 5000, which you can reach at http://localhost:5000. You can then make the file executable and start the server with ./2loop.rb, or just run ruby 2loop.rb if you don't want to make your file executable for some reason.
If you don't want WEBrick just to serve files, you will have to add custom behavior to your web server inside the 2loop.rb script. This is a fairly low-level thing to do, but may suit your needs.
Sensible Alternatives
You should probably use a web framework like Ruby on Rails or Sinatra if you don't want to have write all the low-level behaviors yourself. Sinatra in particular is a very lightweight alternative. This example:
#!/usr/bin/env ruby
require 'sinatra'
set :port, 5000
get '/hello' do
"Hello, World!"
end
will create a URL at http://localhost:5000/hello with a custom action that returns "Hello, World!" as an in-browser response.
Well, I'd suggest you to use Common Gateway Interface (CGI). Let me provide you an example.
Firstly, create a file named server.rb:
require 'webrick'
server = WEBrick::HTTPServer.new(
:Port => 6789, # a server's port
:DocumentRoot => File.join(Dir.pwd, "/scripts") # a folder with scripts
)
server.start
Secondly, create a folder scripts and put the following file (the_best_program.cgi) into it. Note the .cgi extension. It matters. Look here for details on the first line of the script (shebang) if you are working under Windows.
#!/usr/bin/env ruby
require 'cgi'
print "Content-type: text/plain\n\n"
5.times { |i| puts "Hello world #{i}!"}
puts 'So many worlds there. :('
Finally,
Launch your server from command-line (ruby server.rb).
Start browser and go to localhost:6789/the_best_program.cgi (or 0.0.0.0:6789/the_best_program.cgi)
Enjoy!
Notes
You might need to change permissions to your scripts folder / script. On unix-like system do: chmod 755 scripts scripts/the_best_program.cgi.
You can launch not only ruby scripts this way.

Run ruby script on page refresh

I've got a ruby script run-this.rb that outputs live calculations to a text file when I run
ruby run-this.rb > output.txt
However, I need to load this same procedure onto a web server where the Ruby script will run on page load and the web page will read the result from the txt file.
My question is two part,
1) How do you tell the web page to run this script on load?
and
2) How do I output the results of run-this.rb to output.txt on page refresh?
Thanks!
You can build a simple web application with the Sinatra framework that will
Run your script
Save the output in a variable
Write the variable contents to a file
Then also write the variable contents to a HTTP response
I would however advise you to encapsulate your script in a Ruby class, which makes it easier to run from another file. For example, in run-this.rb:
class FooRunner
def self.run!
# write to string instead of printing with puts
result = ''
# do your computations and append to result
result << 'hello, world!'
# return string
result
end
end
# maintain old functionality: when running the script
# directly with `ruby run-this.rb`, simply run the code
# above and print the result to stdout
if __FILE__ == $0
puts FooRunner.run!
end
In the same directory, you can now have a second file server.rb, which will perform the steps outlined in the list above:
require 'sinatra'
require './run-this'
get '/' do
# run script and save result to variable
result = FooRunner.run!
# write result to output.txt
File.open('output.txt','w') do |f|
f.write result
end
# return result to be written to HTTP response
content_type :text
result
end
After installing Sinatra with gem install sinatra, you can start the server with ruby server.rb. The output will tell you where to point your browser:
[2014-01-08 07:06:58] INFO WEBrick 1.3.1
[2014-01-08 07:06:58] INFO ruby 2.0.0 (2013-06-27) [x86_64-darwin12.3.0]
== Sinatra/1.4.4 has taken the stage on 4567 for development with backup from WEBrick
[2014-01-08 07:06:58] INFO WEBrick::HTTPServer#start: pid=92108 port=4567
This means your page is now available at http://127.0.0.1:4567, so go ahead and type this in your browser. Et voilá!
After you have displayed the page, the directory will also contain output.txt with the same contents.

Adding files to redmine via command line

We have an automatic build system that spits out packages, regression-tested & wrapped into a neat installer, ready for end-users to d/l & deploy.
We do tracking of end user support requests/bug reports via redmine. So far we uploaded the packages manually to the resp. 'Files' section of the redmine project, via the web interface.
What I'd like to do is to automate this step.
I imagine this would requires a few lines of Ruby to interface with redmine's db. I have zero knowledge about redmine's internals. :)
Basically I want the equivalent of a
mv package-x.y.z.tbz /usr/local/redmine/files/
as a Ruby (or whatever language suits the need) script that creates the right filename and registers the file in redmine's db so it shows up as if it had been uploaded through the Web interface, manually.
Cheers!
I've been frustrated with Redmine about things like this before. But before I go much further: is there a specific reason why you're using the Files section for this? It seems another tool (such as SSH/SFTP for uploading to someplace accessible to HTTP) might be a better fit for your needs. It would also be easily scriptable. Just point people to some constant URL like http://yourcompany.com/productname-current.zip.
If you really need to use Redmine for managing this, you might check out Mechanize: http://mechanize.rubyforge.org/. They should have a RESTful API also, but I've never used it.
I found this post, hope it can help you
Automating packaging and RedMine
I'm a bit late, but I've wrote a Redmine upload tool in Perl, using the WWW::Mechanize module.
Please find it on http://github.com/subogero/redgit
As already stated, you can use Mechanize for that.
There's a Python script written by Gert van Dijk's: https://github.com/gertvdijk/redmine-file-uploader
To use it you'll have to install Python Mechanize package first:
easy_install mechanize
If you prefer Ruby, you can use:
require 'mechanize'
# Replaces \ with / and removes "
ARGV.map!{|a|a.gsub('\\','/').gsub(/^"(.+)"$/,'\\1')}
filename = ARGV[0] || abort('Filename must be specified')
puts "File: #{filename}"
url = ARGV[1] || abort('Redmine URL must be specified')
puts "Redmine URL: #{url}"
username = ARGV[2] || abort('Redmine username must be specified')
puts "Username: #{username}"
password = ARGV[3] || abort('Redmine password must be specified')
puts "Password: #{'*' * password.length}"
project = ARGV[4] || abort('Redmine project must be specified')
puts "Project: #{project}"
login_page_path = '/login'
files_page_path = '/projects/' + project + '/files'
agent = Mechanize.new
# No certificate verification (I had to use this hack because our server is bound to custom port)
# agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
agent.get(URI.join(url, login_page_path)) do |login_page|
login_page.form_with(:action => login_page_path) do |login_form|
login_form.username = username
login_form.password = password
end.submit
end
agent.get(URI.join(url, files_page_path + '/new')) do |upload_page|
upload_page.form_with(:action => files_page_path) do |upload_form|
upload_form.file_uploads.first.file_name = filename
end.submit
end
And don't forget to install gem first:
gem install mechanize

Resources