Rick Strahl's Weblog
Rick Strahl's FoxPro and Web Connection Weblog
White Papers | Products | Message Board | News |

Doing HTTP Headers right in Web Connection 5.0


2 comments
June 22, 2006 •

The new Web Connection wwPageResponse object makes it much easier to manipulate HTTP headers by directly exposing various header constructs and allowing headers to be set during the course of the request and not just at the beginning as in previous versions.

 

In older versions of Web Connection if you needed to custom headers, or wanted to add cookies you generally were forced to the use a wwHTTPHeader object instance and call methods on it to add headers or otherwise modify the HTTP header through the class interface. You then had to take this object and either call Response.ContentTypeHeader() or pass the header object to any Response method that supported this object as a parameter such as ExpandTemplate, ExpandScript and various others.

 

In Web Connection 5.0 the wwPageResponse does away with the external requirement of wwHTTPHeader and instead lets you manipulate the HTTP header directly on the response object.

 

Here are a few examples:

 

Adding a custom header to the Response

 

Response.Headers.Add("MyHeader",TRANS(DateTime()))

 

Note that in Web Connection 5.0 with the wwPageResponse class you can write a header at any time, unlike in previous versions where the header had to be written first. Web Connection now always buffers the output in memory first and then adds the header at the very end.

 

Changing the Content Type of a Request

 

lcXML = CursorToXml(…)

Response.Write(lcXML)

 

*** Note that I can write the Content Type later on!

Response.ContentType = "text/xml"

 

The same logic also applies to Web Control Framework Pages. You can work on the page as needed and generate output and change the header anywhere in your page code. Web Connection will still add the header just before the final response gets generated.

 

Returning a 404 – File not Found Response

 

Response.Clear()

Response.Status = "404 File not found"

Response.Write("Page was not found")

 

If you need to write out different HTTP status codes you can do so easily now with the Status page. Web Connection generates out of this:

 

HTTP/1.1 404 File not found

Content-Type: text/html

 

Page was not found

 

Adding Cookies to the Response

 

FUNCTION HeaderTest

 

lcTime = Request.GetCookie("MyCookie")

 

IF EMPTY(lcTime)

      lcTime = TRANSFORM(DATETIME())

      Response.AddCookie("MyCookie",lcTime,"/",DATETIME() + 10)

ENDIF

     

*** Note Standard Page automatically picks up the headers  

Process.StandardPage("Cookie Test",
                 
"This cookie value should stay the same for 10 seconds, " +;
                  "then change to a new value."
+ ;

                  "<br /><br />The Cookie time value is: " + lcTime)

 

ENDFUNC

 

This example sets a new cookie with a 10 second timeout and displays the cookie value. If you refresh this page repeatedly you’ll see the cookie value stay the same for 10 seconds then change and stay the same for 10 more seconds and so on.

 

There’s also a Response.Cookies collection which you can clear and manually edit. The collection consists of the name of the cookie as the key and the raw formatted cookie string that will be sent to the browser which looks like this:

 

MyCookie=06/22/2006 02:48:39 AM; path=/; expires=Thu, 22 Jun 2006 09:48:49 GMT

 

Writing a complete HTTP Header

Internally Web Connection uses this functionality as well. Here’s an example of Response.BasicAuthentication() which writes the Basic Authentication Challenge header and essentially creates the entire response using various header constructs (this refers to the Response object):

 

FUNCTION BasicAuthentication(tcRealm, tcErrorText)

tcRealm     = IIF(VARTYPE(tcRealm)="C",tcRealm,"")

tcErrorText = IIF(VARTYPE(tcErrorText)="C",tcErrorText,;

                "<HTML><body><h1>Access to this page is denied</h1><hr>"+CR+;

                "Please enter a valid username and password to access this page.</body></HTML>")

 

THIS.Clear()

this.Status = "401 Not Authorized"

this.Headers.Add("WWW-Authenticate",[basic realm="]+ tcRealm + ["])

 

IF !EMPTY(tcErrorText)

   this.FastWrite(tcErrorText)

ENDIF

 

THIS.End()

 

Note that Response.Headers.Add() is used and can be used for just about any HTTP headers you need to write as simple key value pairs. Here’s another internal example in Response.AddForceReload() which makes sure that a particular request does not get cached:

 

FUNCTION AddForceReload()

 

this.Expires="0"

THIS.Headers.Add("Pragma","no-cache")

this.Headers.Add("Cache-Control","no-cache")

THIS.Headers.Add("Cache-Control","post-check=0,pre-check=0")

 

ENDFUNC

 

Clearing Headers and duplicate Headers

The Response.Headers object is a standard wwNameValueCollection class so you can call Response.Headers.Clear() to clear all headers. Be careful with this though since other code may have set headers that might be vital (such as cookies). Generally you won’t need to clear headers unless you’re writing out an error or challenge response.

 

The Response.Headers is a collection so duplicates are not allowed – wwNameValueCollection will automatically overwrite a value that already exists so you don’t have to worry about duplicate header entries.

 

Response.Headers.Add("RequestId","_INVALID_ID_1")

Response.Headers.Add("RequestId","_INVALID_ID_2")

 

Will cause only the second value to be written to the header.

 

 

So, as you can see nowhere in these samples was there a need to use an wwHTTPHeader object. Instead you can simply use the native properties and methods of the Response object. Note though that all of this works only if you use the wwPageResponse object, which is used by default for new projects. However, if you have pre-Web Connection 5.0 projects you may still be using the older wwResponse, wwResponseFile, wwResponseString objects. Check the Web Connection 5.0 upgrade documentation on what needs to happen to migrate the Response object – for the most part this port is minor, but very worthwhile. The ability to change headers later on in the page cycle is very useful.

Posted in:

Feedback for this Weblog Entry


re: Doing HTTP Headers right in Web Connection 5.0



Michael Hogan
August 13, 2017

Very helpful - but how would I return a 301 redirect? In my 5.x app, I do this: Response.Clear() Response.Status = "404 File not found" Response.Write("Page was not found")

TIA

re: Doing HTTP Headers right in Web Connection 5.0



Rick Strahl
August 13, 2017

Easy:

Response.Redirect("~/default.wcs",.T.)

The .T. parameter makes a permanent redirect.

 
© Rick Strahl, West Wind Technologies, 2003 - 2024