I'm trying to make a CGI program with Haskell. (using Apache)
But my program cannot print UTF-8 string correctly.
module Main where
main :: IO()
main = do
{
putStr("Content-type: text/plain; charset=utf-8\n\n");
putStr("English한글日本語abc");
}
Result checked via telnet is:
hhmm:appserve Eonil$ telnet localhost 80
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET http://localhost/cgi-bin/test HTTP\1.0
HTTP/1.1 200 OK
Date: Mon, 07 Mar 2011 07:31:28 GMT
Server: Apache/2.2.15 (Unix) mod_ssl/2.2.15 OpenSSL/0.9.8l DAV/2
Connection: close
Content-Type: text/plain; charset=utf-8
EnglishConnection closed by foreign host.
hhmm:appserve Eonil$
What's the problem and what should I do to fix this?
PS. The program printed well on command-line console. And apache CGI built with shell script printed UTF-8 string well.
To make sure putStr uses the right encoding you can call hSetEncoding on stdout to set it to "utf8".
http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.3.1.0/System-IO.html#g:23
Related
I'm trying to send a voice message from a Telegram BOT, without success.
As a proof of concept I'm trying to do that by using curl:
#!/bin/bash
TOKEN=$(cat .token)
CHAT=$(cat .chat)
URL="http://server2.mbrt.it:8080/static/foo.ogg"
curl "https://api.telegram.org/bot$TOKEN/sendVoice?chat_id=$CHAT&voice=$URL"
But I keep getting:
{"ok":false,"error_code":400,"description":"Bad Request: wrong file identifier/HTTP URL specified"}
I'm sure that both the token and the chat id are correct, because I'm able to send audio with the sendAudio method (sending an mp3 file). The URL I'm using is public, a wget from any PC will download the file.
The HTTP headers are also correct AFAIK (note the Content-Type header):
$ curl -v http://server2.mbrt.it:8080/static/foo.ogg >/dev/null
< HTTP/1.1 200 OK
< Server: nginx/1.10.3
< Date: Fri, 09 Jun 2017 14:14:11 GMT
< Content-Type: audio/ogg
< Content-Length: 5881
< Last-Modified: Thu, 08 Jun 2017 23:23:21 GMT
< Connection: keep-alive
< ETag: "5939dc69-16f9"
< Accept-Ranges: bytes
My guess was that my encoding was wrong in some way:
$ file foo.ogg
foo.ogg: Ogg data, Opus audio,
But I tried to encode it either with ffmpeg, opusenc and oggenc. In all cases I get the same error when I send it.
I have no idea of what I'm doing wrong.
I tried it on my own VPS, seems Telegram only accept port 80 for HTTP, and port 443 for HTTPS :(
You can download it, and use curl -F "voice=#foo.ogg" to upload it yourself.
I cant access a specific filetype on my customer server (production).
Here are the results with cURL:
curl "http://domain.tld/fonts/glyphicons-halflings-regular.eot" -I
HTTP/1.1 200 OK
Date: Tue, 28 Jul 2015 12:06:23 GMT
Server: Apache/2.2.15 (Red Hat)
Last-Modified: Tue, 19 May 2015 15:32:20 GMT
ETag: "14023-4f42-516710421e900"
Accept-Ranges: bytes
Content-Length: 20290
Connection: close
Content-Type: application/vnd.ms-fontobject
The file is here.
But when I try to get the file content:
curl "http://domain.tld/fonts/glyphicons-halflings-regular.eot"
curl: (56) Recv failure: Connection was reset
I can't (yet) access the customer server, so I'm trying to guess what's wrong here.
What is working so far:
curl "https://domain.tld/fonts/glyphicons-halflings-regular.eot" --insecure
It is working in HTTPS, even if there is no certificate (which is why I use --insecure). I get the file content.
The customer can get the file if he accesses the file from a local URL.
I can access all other files on the server, even in the fonts directory.
I can't access all .eot files, even in other directories.
So I think it is one of those 2 problems:
- Apache configuration / .htaccess problem.
- Proxy / reverse proxy problem.
What do you think about it?
What kind of other test should I do?
What information should I ask to the customer?
Thanks.
Ok, here is the cause:
The customer firewall blocks .eot file content.
A vulnerability in Embedded Web Fonts Could Allow Remote Code Execution.
http://www.checkpoint.com/defense/advisories/public/2006/cpai-2006-010.html
As the .eot files are used by IE8 and lower, and those browser versions are not required by the customer, I've simply removed all references to .eot files.
Another solution would be to ask for the customer firewall admins to add an exception, as the severity is low.
I am playing with tclhttpd web server and found a strange error
I start tclhttpd at default port 8015
Open firefox and navigate to http://localhost:8015
I see source of my index.html file instead of web page.
index.html is simple ( < and > are skipped ):
html
head
title
TEST
/title
/head
body
H1 TEST HEADER /H1
/body
/html
Any ideas?
I have checked with the curl:
* About to connect() to localhost port 8015 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8015 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.21.3 (i386-pc-win32) libcurl/7.21.3
OpenSSL/0.9.8q zlib/1.2.5
> Host: localhost:8015
> Accept: */*
Server Response
HTTP/1.1 200 Data follows
Date: Thu, 12 Apr 2012 14:16:47 GMT
Server: Tcl-Webserver/3.5.1 May 27, 2004
Content-Type: text/plain
Content-Length: 130
Last-Modified: Thu, 12 Apr 2012 14:14:30 GMT
So, tclhttpd returns text/plain instead of text/html
Linux case
I have tried to check what would happened with Linux.
As tclkttpd is wrapped in kit I made the same test under Linux.
It looks like everything works fine.
curl -G -v localhost:8015
* About to connect() to localhost port 8015 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8015 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.21.7 (i686-pc-linux-gnu) libcurl/7.21.7
OpenSSL/1.0.0d zlib/1.2.5 libssh2/1.2.7
> Host: localhost:8015
> Accept: */*
Server response
HTTP/1.1 200 Data follows
Date: Thu, 12 Apr 2012 17:25:29 GMT
Server: Tcl-Webserver/3.5.1 May 27, 2004
Content-Type: text/html
Content-Length: 125
Last-Modified: Thu, 12 Apr 2012 17:14:04 GMT
Deep research
I have modified some of the source files, to dump more information:
proc Mtype {path} {
global MimeType
set ext [string tolower [file extension $path]]
Stderr "Mtype: path $path ext $ext"
if {[info exist MimeType($ext)]} {
Stderr "MimeType($ext) exists."
Stderr "Print MimeType "
set lst [lsort [array names MimeType]]
foreach {i} $lst {
Stderr " $i $MimeType($i)"
}
return $MimeType($ext)
} else {
Stderr "Mimetype not found. ext $ext"
Stderr "Print MimeType "
set lst [lsort [array names MimeType]]
foreach {i} $lst {
Stderr " $i $MimeType($i)"
}
return text/plain
}
}
When I query http://localhost:8015
I got following output:
Linux
Mtype: path /home/a2/src/tcl/tcl_www/doc/index.html ext .html
MimeType(.html) exists.
Print MimeType
text/plain
.ai application/postscript
.aif audio/x-aiff
.aifc audio/x-aiff
....
.hqx application/mac-binhex40
.htm text/html
.html text/html
.i86pc application/octet-stream
...
Default cmd Doc_text/html
Windows
Look for Tcl proc whos name match the MIME Content-Type
Mtype: path M:/apr/tcl_www/doc/index.html ext .html
Mimetype not found. ext .html
Print MimeType
.man application/x-doctool
Mtype M:/apr/tcl_www/doc/index.html returns Doc_text/plain
So it look like there are troubles with reading mime.types
You have to inspect the traffic tclhttpd generates to see if it really says in the HTTP headers of its response that the payload type is "text/html".
Use Fiddler, sockspy, Microsoft Network Monitor or Wireshark.
Also there are lighter-weight debugging tools for browsers. I'm pretty sure Firebug wold show you this information, and even simple Live HTTP Headers can do that.
IE also has some debugging addon (akin to Firebug) which I'm lazy to google for.
Problem found.
httpdthread.tcl
# Core modules
package require httpd ;# Protocol stack
package require httpd::version ;# Version number
package require httpd::url ;# URL dispatching
package require httpd::mtype ;# Mime types
# Search for mime.types either right in Config(lib), or down
# one level in the installed tclhttpd subdirectory
foreach path [list \
[file join $Config(lib) mime.types] \
[glob -nocomplain [file join $Config(lib) tclhttpd* mime.types]] \
] {
if {[llength $path] > 0} {
set path [lindex $path 0]
}
if {[file exists $path]} {
Mtype_ReadTypes $path
break
}
}
This code checks for the mime.types file under following paths:
- /home/a2/..../tclhttpd3.5.1.kit/bin/../lib
- /home/a2/..../tclhttpd3.5.1.kit/bin/../lib/tclhttpd*/mime.types
Linux
glob -nocomplain /home/..../tclhttpd3.5.1.kit/bin/../lib/tclhttpd*/mime.types]
works fine and returns
/home/....tclhttpd3.5.1.kit/bin/../lib/tclhttpd3.5.1/mime.types
Windows
glob -nocomplain /home/..../tclhttpd3.5.1.kit/bin/../lib/tclhttpd*/mime.types]
failed.
I have tried different masks:
tclhttpd*
tclhttpd*.*
tclhttpd*..
nothing is working
Finally I have modified the code:
foreach path [list \
[file join $Config(lib) mime.types] \
[glob -nocomplain [file join $Config(lib) tclhttpd* mime.types]] \
[file join $Config(lib) [lindex [Httpd_Version] 0] mime.types]
] {
if {[llength $path] > 0} {
set path [lindex $path 0]
}
if {[file exists $path]} {
Mtype_ReadTypes $path
break
}
}
string
[file join $Config(lib) [lindex [Httpd_Version] 0] mime.types]
generate the path:
/home/..../tclhttpd3.5.1.kit/bin/../lib/tclhttpd3.5.1/mime.types
Now tclhttpd could find mime.types under windows.
And it looks like that problem happened only if glob is searching inside the statkit file.
I have checked with the fresh tclkitsh and tclhttpd
tclkitsh-8.5.9-win32.upx.exe ( http://code.google.com/p/tclkit/downloads/list )
tclhttpd5.3.1.kit
Everything works.
If I use my "old" version of tclkitsh-win32.upx.exe
I receive text/plain instead of text/html
So it looks like there is a bug in my old wrapped interpretor, that leads to the problem with not reading mime.types.
I think tclhttpd automatically uses text/html if the file ends with .html. You properly should read this wiki entry on wiki.tcl.tk about mime-type.
Tried it myself with a index.html and it worked. Than I created an index.tml and it worked.
[html::description "Test"]
[Doc_Dynamic]
[html::head "hello"]
<body>
test
</body>
</html>
Here is the header part of the response:
HTTP/1.1 200 Data follows
Content-Length: 137
Date: Thu, 12 Apr 2012 16:47:53 GMT
Server: Tcl-Webserver/3.5.1 May 27, 2004
Connection: Close
Content-Type: text/html
The reason for curl getting text/plain instead of text/html might be that it passes */* in the Accept header of its HTTP requests, while typically browsers place some more elaborate construct there—for instance, my FF 11.0 uses text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8.
One might notice that in the FF's case text/html (along with XHTML and XML types) is assigned a higher preference (0.9) and everything else (*/*) is assigned a lower preference (0.8).
A conformant HTTP server should attempt to serve the requested resource in a format indicated as preferred in the client's request.
Probably that might also shed some light on that original IE vs FF behavioral difference.
I'm using Nginx + uwsgi + python3
Sending any header via start_response goes well, but when I want to send more than one header, it becomes mad.
For example, if I write:
start_response('200 OK', [('Last-Modified', 'Wed, 11 Jan 2012 00:00:00 GMT'), ('Content-Type', 'text/html; charset=windows-1251')])
The headers sent are:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: nginx/1.0.11
Connection: close
Date: Wed, 11 Jan 2012 04:17:22 GMT
Content-Type: text/html; charset=windows-1251
Content-Type: text/html; charset=windows-12
uwsgi sends the same header twice and even more the second one is broken.
which uWSGI and nginx version ? In both 0.9.8.x and 1.0.x i cannot reproduce your error.
You can check the real headers sent by uWSGI putting it in http mode with --http/--http-socket
I need to either find a file in which the version is encoded or a way of polling it across the web so it reveals its version. The server is running at a host who will not provide me command line access, although I can browse the install location via FTP.
I have tried HEAD and do not get a version number reported.
If I try a missing page to get a 404 it is intercepted, and a stock page is returned which has no server information on it. I guess that points to the server being hardened.
Still no closer...
I put a PHP file up as suggested, but I can't browse to it and can't quite figure out the URL path that would load it. In any case I am getting plenty of access denied messages and the same stock 404 page. I am taking some comfort from knowing that the server is quite robustly protected.
The method
Connect to port 80 on the host and send it
HEAD / HTTP/1.0
This needs to be followed by carriage-return + line-feed twice
You'll get back something like this
HTTP/1.1 200 OK
Date: Fri, 03 Oct 2008 12:39:43 GMT
Server: Apache/2.2.9 (Ubuntu) DAV/2 SVN/1.5.0 PHP/5.2.6-1ubuntu4 with Suhosin-Patch mod_perl/2.0.4 Perl/v5.10.0
Last-Modified: Thu, 02 Aug 2007 20:50:09 GMT
ETag: "438118-197-436bd96872240"
Accept-Ranges: bytes
Content-Length: 407
Connection: close
Content-Type: text/html; charset=UTF-8
You can then extract the apache version from the Server: header
Typical tools you can use
You could use the HEAD utility which comes with a full install of Perl's LWP library, e.g.
HEAD http://your.webserver.com/
Or, use the curl utility, e.g.
curl --head http://your.webserver.com/
You could also use a browser extension which lets you view server headers, such as Live HTTP Headers or Firebug for Firefox, or Fiddler for IE
Stuck with Windows?
Finally. if you're on Windows, and have nothing else at your disposal, open a command prompt (Start Menu->Run, type "cmd" and press return), and then type this
telnet your.webserver.com 80
Then type (carefully, your characters won't be echoed back)
HEAD / HTTP/1.0
Press return twice and you'll see the server headers.
Other methods
As mentioned by cfeduke and Veynom, the server may be set to return limited information in the Server: header. Try and upload a PHP script to your host with this in it
<?php phpinfo() ?>
Request the page with a web browser and you should see the Apache version reported there.
You could also try and use PHPShell to have a poke around, try a command like
/usr/sbin/apache2 -V
httpd -v will give you the version of Apache running on your server (if you have SSH/shell access).
The output should be something like this:
Server version: Apache/2.2.3
Server built: Oct 20 2011 17:00:12
As has been suggested you can also do apachectl -v which will give you the same output, but will be supported by more flavours of Linux.
Warning, some Apache servers do not always send their version number when using HEAD, like in this case:
HTTP/1.1 200 OK
Date: Fri, 03 Oct 2008 13:09:45 GMT
Server: Apache
X-Powered-By: PHP/5.2.6RC4-pl0-gentoo
Set-Cookie: PHPSESSID=a97a60f86539b5502ad1109f6759585c; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Content-Type: text/html
Connection to host lost.
If PHP is installed then indeed, just use the php info command:
<?php phpinfo(); ?>
Rarely, a hardened HTTP server is configured to give no server information or misleading server information. In those scenarios if the server has PHP enabled you can add:
<?php phpinfo(); ?>
in a file and browse to it and look for the
_SERVER["SERVER_SOFTWARE"]
entry. This is susceptible to the same hardening lack of information/misleading though I would imagine that it's not altered often, because this method first requires access to the machine to create the PHP file.
The level of version information given out by an Apache server can be configured by the ServerTokens setting in its configuration.
I believe there is also a setting that controls whether the version appears in server error pages, although I can't remember what it is off the top of my head. If you don't have direct access to the server, and the server administrator is competent and doesn't want you to know the version they're running... I think you may be SOL.
Telnet to the host at port 80.
Type:
get / http1.1
::enter::
::enter::
It is kind of an HTTP request, but it's not valid so the 500 error it gives you will probably give you the information you want. The blank lines at the end are important otherwise it will just seem to hang.
If they have error pages enabled, you can go to a non-existent page and look at the bottom of the 404 page.
Your best option is through PHP:
All version requests from the client side cannot be trusted since your Apache could be configured with ServerTokens Prod and ServerSignature Off. See: http://www.petefreitag.com/item/419.cfm
In the default installation, call a page that doesn't exist and you get an error with the version at the end:
Object not found!
The requested URL was not found on this server. If you entered the URL manually please
check your spelling and try again.
If you think this is a server error, please contact the webmaster.
Error 404
localhost
10/03/08 14:41:45
Apache/2.2.8 (Win32) DAV/2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5
Simply use something like the following - the string should be there already:
<?php
if(isset($_SERVER['SERVER_SOFTWARE'])){
echo $_SERVER['SERVER_SOFTWARE'];
}
?>
Use this PHP script:
$version = apache_get_version();
echo "$version\n";
Se apache_get_version.