You are not logged in Log in Join
You are here: Home » Members » jim » ZopeSecurity » GetAndPostToSamePage » wikipage_view

Log in
Name

Password

 
 
FrontPage »

GetAndPostToSamePage

New Standard Idiot: GET and POST to same page

In the beginning there was Bobo and it was good. In our innocence, we used pages to display the state of an objects with an editing interface (e.g. manage_main), and methods to do the edit (manage_edit). After performing an edit, we'd typically just call the display page (manage_main) from manage_edit. This seemed to work well for a while.

Later, we noticed that the display page would sometimes get confused because it was displayed via the "wrong" URL. To get around this, we started using redirects to make the browser visit the display page after the edit. This has the obvious downside of causing a separate request to be made. Also, some clients may not handle redirects predictably.

An alternative would be to use the same URL for display and edit. A display page could be written in such a way that if a request was a POST, the edit method would be called internally before executing the display logic. If there was an input error, then the form would be displayed with the data from the request and any input error messages.

A simple example.

Suppose we have an object that has an interface for managing two properties, title and text. Title is a simple string and text is a possibly-multi-line string.

We might have something like:

       <html><body>

          <dtml-form post="main_post" 
             errors="errors,title_error,text_error">

             <dtml-if errors>
               <hr><font color="red"><ul>
                  <dtml-in errors>
                    <li>&dtml-sequence-var;</li>
                  </dtml-in>                    
               </ul></font><hr>
             </dtml-if>

             Title: 
                <dtml-if title_error>
                  <font color="red">&title_error;</font>
                </dtml-if>
                <br><input name=title value="&dtml-title;">
             Text: 
                <dtml-if text_error>
                  <font color="red">&text_error;</font>
                </dtml-if>
                <br><textarea name="text:text">value="&dtml-text;">

             <input type="submit">
          </dtml-form>
       </body></html>

We could do this without a new tag. But the example wouldn't be so simple. ;)

Zen
This example will of course raise a KeyError?, as the values for the input controls will not render during the initial viewing of the form. The simple fix for this is to add another attribute to the dtml-form, which specifies a populate object to populate REQUEST with required values (eg. set them to empty strings, default values or pull from a SESSION). We could also move the automatic variable type checking into the <dtml-form> tag.

For example:

        <html><body>

          <dtml-form post="main_post" validate="main_validate"
            populator="SESSION" 
            controls="title,text:text,priority:int"
            errors="errors,title_error,text_error">

            <p>main_post will only be called if neither
             main_validate or the Zope internal type checking
            (priority:int) returns any errors.

            <dtml-if errors>
              <hr><font color="red"><ul>
                 <dtml-in errors>
                   <li>&dtml-sequence-var;</li>
                 </dtml-in>                    
              </ul></font><hr>
            </dtml-if>

            Title: 
               <br><input name=title value="&dtml-title;">
            Priority:               
               <br><input name=priority value="&dtml-priority;">
            Text: 
               <br><textarea name=text value="&dtml-text;">
             <input type="submit">
          </dtml-form>
          </body></html>

ChrisW?
I actually like the idea of the new tag. It makes things nice and clean :-)

The dtml-form tag:

  • generates a HTML form tag, using the request URL as the action.
  • If the request method is POST:
    • Makes sure that REQUEST['HTTP_REFERER']==REQUEST['URL'], to protect against trojans. ;)

      Could this be optional? Could you supply a list of acceptable referers? I can think of ocassions when it's useful to have two seperate forms handled by the same action.

      PJE
      not only that, but what do you do about clients which don't send referrers? What about XML-RPC POST operations? Maybe this should be implemented using different method names, e.g. GET and POST instead of index_html. POST could call GET if errors are present. No tags needed, cleaner seperation of functionality...?
    • Securely calls the method given in the post attribute, main_post.
      Note
      We need a way of expressing that a method is callable by DTML but not callable through the web.... And the other way around.
      ChrisW?
      I suggested this on the ZopeDev? list on 11/12/99 as Execute permission thoughts... but didn't get any response :(
      ChrisW?
      This had another airing on the ZopeDev? list recently (May 2000) and lots of interesting views were expressed. Maybe someone could pick one and implement it? ;-)
    • If the result of calling POST is None:
      • Adds the names mentioned in the "errors" attribute to the namespace with empty strings as values.

      Otherwise:

      • Pushes REQUEST to the top of the namspace stack.
      • Adds the names mentioned in the "errors" attribute to the namespace with empty strings as values.
      • Adds the attributes of the result of calling POST to the namespace.
  • If the request method is GET:

    Adds the names mentioned in the "errors" attribute to the namespace with empty strings as values.

I've been thinking of a facility like this for a while. What finally pushed me over the edge was Emacs W3 v4.0 whining about a redirect after editing a wiki page. Would this facility help? Hm. Well, not exactly. With Wiki pages, there are three pieces:

  • The normal view
  • The edit view
  • The edit action

Currently, you view the normal view, follow a link to the edit view, POST to the edit action, which redirects to the normal view.

The POST would need to go to the normal view. If there aren't any errors, then we display the nrmal view with updated data. If there are errors, we would need to display the edit view with the errors. This might be a bit weird, although I think I could live with it.

The implementation would be a bit different, since the normal view a Python method, not a DTML method. Also, the HTTP_REFERER check would have to allow the normal view or the edit view.


I just implemented a form in this way. Here's the code, as food for thought: GetAndPostExampleOne --ZWikiWeb:SimonMichael


JHT

I've done systems this way. Works fine from the perspective of the web server, but not so well from the perspective of the user. What happens is that a user fills out a form and submits it. They get back the results and then go to the next page. Now if they try to use the back arrow to see the results again, the browser wants to repost the form before it will display the page again. The redirect scheme gets around this problem.