How to send a custom http status code with mod_perl
Asked Answered
T

1

8

I have written a CGI program and I send a status error with the HTTP header to the client. but when I tried to use mod_perl it only responds with 200 ok status. How can I send a custom status code?

here is the code when I want to respond with the custom status error :

my $cgi      = new CGI;
print $cgi->header(-type=>"text/html", -charset=>'utf-8', -status=>599);

EDIT :
here is the code :

#!/usr/bin/perl -w
use strict;
use warnings;
use CGI;
use SessionManagement;


my $cgi      = new CGI;
my $method = $cgi->param("method");

my $sessionManagement = new SessionManagement(cgi=>$cgi);
if($sessionManagement){

  if (defined($method)) {
    if($method eq "authentication") {
        loginMethod($cgi,$sessionManagement);
    } elsif ($method eq "someMethod"){
        someMethod($cgi);
    } else{
        print $cgi->header(-type=>"text/xml", -charset=>'utf-8');
        print "<html>method does not exist</html>";
    }

  } else {
      print $cgi->header(-type=>"text/html", -charset=>'utf-8' , -status=>599);
      print "<html>blah blah</html>";
  }

}else{
  print $cgi->header(-type=>"text/html", -charset=>'utf-8' , -status=>599);
  print "<html>blah blah</html>";
}

-------------------------------------------

EDIT 2

giving some more information: when I use curl -v 192.168.1.212/mymodperl/test.pl command in shell.
here is the response :

* About to connect() to 192.168.1.212 port 80 (#0)
*   Trying 192.168.1.212... connected
* Connected to 192.168.1.212 (192.168.1.212) port 80 (#0)
> GET /mymodperl/test.pl HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 192.168.1.212
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 25 Nov 2017 11:04:18 GMT
< Server: Apache/2.2.15 (Red Hat)
< Connection: close
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=ISO-8859-1
< 
<html>hi</html><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator,
 root@localhost and inform them of the time the error occurred,
and anything you might have done that may have
caused the error.</p>
<p>More information about this error may be available
in the server error log.</p>
<hr>
<address>Apache/2.2.15 (Red Hat) Server at 192.168.1.212 Port 80</address>
</body></html>
* Closing connection #0
Tympanites answered 23/11, 2017 at 8:28 Comment(25)
You do realise this is 2017 right?Oneeyed
@GerhardBarnard I do :))Tympanites
ok, where is the mod_perl portion you are experiencing the issues with?Oneeyed
also, putting my answer on hold until I get clarity from you and will repost.Oneeyed
@GerhardBarnard what do you mean by "where is the mod_perl portion"? I have placed my code in mod_perl directory and called it with a browser, it runs by mod_perl. but the statuses I have set do not work.Tympanites
that is what I mean, show me how you call it and your directory structureOneeyed
Can you run a curl -v <url> for the one where you expect 599 code and post the output that you get in your question? Status is the first thing that should go back, and I guess it might be a case of header order errorForeside
You should try using $cgi->$header->status('599 Some Issue'); before printing or setting any headerForeside
@TarunLalwani I did 'curl -v <myUrl>' and I got 200 ok again. I cleared all the other header settings except status, and still have the same problem.Tympanites
I think this is a mod_perl issue, there must be some other way to set header status in mod_perl, That is because I have no problem running the code in CGI mode.Tympanites
@TarunLalwani I edited the question and added the response of curl too.Tympanites
Using mod_perl for writing web applications is not recommended. Have you considered something PSGI based?Lenzi
Works fine for me on Apache/2.4.18, could it be because of older apache version? Can you try with latest one?Foreside
did you try it with mod_perl ??? @TarunLalwaniTympanites
I think i mixed CGI and mod perl. Let me try that outForeside
You could simply print the header that you want. There isn't any real magic in what CGI->header is doing. I would also recommend using a valid HTTP return code.Surtout
Do not use perl module CGI anymore, and do not invent new HTTP codes.Callant
@Lenzi Thank you for your suggestion, but at this time I need to make it work with mod_perl (not my choice). but I'll consider your advice for later apps. Thanks.Tympanites
@JimBlack actually I have sent other valid codes and it still is not working. so I know that the problem is not with sending the HTTP valid code.Tympanites
@PatrickMevzek I suggest you read the question thoroughly. I am using mod_perl and I need to use a custom code. if you had any solutions in mind I'd be happy to hear it.Tympanites
Do not invent new HTTP codes, whatever software you use. There is a standard, and it is not there to extend it personnally with any new codes... of course if you want interoperability and following standards. You nowhere gave any valid reason to create a new response value. Imagine if everyone does like you, how do you think the web could work?Callant
There is no law against using a custom HTTP code. and there are no boundaries in programming. The way to do it is in the answers below. if I want to do sth I make it work. That is the way to push the limits. I like to have a growing mindset.Tympanites
You are wrong, there is a "law". HTTP is a protocol defined by IETF RFCs. They do not say you are free to decide unilateraly to create new status codes. This has nothing to do with a "growing mindset".Callant
@PatrickMevzek RFCs are not laws. they define some rules and protocols and standards. breaking these rules or standards does not put you in jail !!! plus it's doable. It's also acceptable to even create a custom protocol as long as your applications understand it, and works fine with it. I don't have information about your country/state laws, it may be a law in your region. but as long as I remember there is no such a thing written in RFC 2616.Tympanites
Playing on words does not lead to anything fruitful. Standards are there for a reason, starting with interoperability. If you prefer to break everything and do your thing alone in your corner, you are right you are technically free to do so. But it does not mean it is a good idea at all. EOT.Callant
S
3

From http://www.perlmonks.org/?node_id=826769, the way to set a status code is

package My::Handler;

use strict;
use warnings 'all';
use Apache2::RequestRec;

sub handler : method {
  my ($class, $r) = @_;

  $r->status( 401 );
  return 401;
}

1;# return true:

EDIT: Clarification

From https://perl.apache.org/docs/2.0/user/handlers/intro.html

What are Handlers?

Apache distinguishes between numerous phases for which it provides hooks (because the C functions are called ap_hook_) where modules can plug various callbacks to extend and alter the default behavior of the webserver. mod_perl provides a Perl interface for most of the available hooks, so mod_perl modules writers can change the Apache behavior in Perl. These callbacks are usually referred to as handlers and therefore the configuration directives for the mod_perl handlers look like: PerlFooHandler, where Foo is one of the handler names. For example PerlResponseHandler configures the response callback.

A typical handler is simply a perl package with a handler subroutine. For example:

file:MyApache2/CurrentTime.pm
----------------------------
package MyApache2::CurrentTime;

use strict;
use warnings;

use Apache2::RequestRec ();
use Apache2::RequestIO ();

use Apache2::Const -compile => qw(OK);

sub handler {
  my $r = shift;

  $r->content_type('text/plain');
  $r->print("Now is: " . scalar(localtime) . "\n");

  return Apache2::Const::OK;
}
1;

This handler simply returns the current date and time as a response.

Since this is a response handler, we configure it as a such in httpd.conf:

PerlResponseHandler MyApache2::CurrentTime

Since the response handler should be configured for a specific location, let's write a complete configuration section:

PerlModule MyApache2::CurrentTime
<Location /time>
  SetHandler modperl
  PerlResponseHandler MyApache2::CurrentTime
</Location>

Now when a request is issued to http://localhost/time this response handler is executed and a response that includes the current time is returned to the client.

Stag answered 26/11, 2017 at 13:51 Comment(10)
I have read this before but I don't know how to use this in my own code. @StagTympanites
The OP is not writing a mod_perl handler; they are writing a Registry script.Reseat
@SarahAziziyan, it seems this cannot be done using a registry script. So the way you are doing it won't allow you to change the status. You will need to use a handler to make it workForeside
@Stag I will try to use a handler as you mentioned, and I'll inform you if it worked. thanks.Tympanites
@TarunLalwani I'll try to use a handler.Tympanites
@Stag I tried to use a handler but as far as I read, handlers can handle requests from specific URLs. In my case (the code that I wrote in the question), I need to send an error msg to the user with some status (sth like 599) in the case when they don't send a parameter called 'method'. but I don't want to send the same error status for all the requests coming to the test.pl.Tympanites
If you like, we can take this into chat.Stag
Thank you for your time and energy @mikep. you were a huge help.Tympanites
@Sarah Aziziyan, happy to help :)Stag
@TarunLalwani Of course you can set the status using a registry script. You can get the request object with my $r = Apache2::RequestUtil->request;, or via an initial $r = shift() in the script. Of course it's better to enclose the whole script in a subroutine and then call that subroutine passing the request object as argument, similar to using the handler method in a perl handler module.Kyoko

© 2022 - 2024 — McMap. All rights reserved.