|
| 1 | +package examples::dynamic_content; |
| 2 | +use Dancer ':syntax'; |
| 3 | +use strict; |
| 4 | +use warnings; |
| 5 | +use POSIX qw(strftime); |
| 6 | +use Data::Dumper; |
| 7 | + |
| 8 | +=pod |
| 9 | +This module demonstrates returning dynamic content to the user from a Dancer route handler. |
| 10 | +
|
| 11 | +The data is generated on-line, without having to temporarily store it in a file or in memory. |
| 12 | +=cut |
| 13 | + |
| 14 | +# Show the main page to the user |
| 15 | +get '/dynamic_content' => sub { |
| 16 | + template 'examples/dynamic_content.tt'; |
| 17 | +}; |
| 18 | + |
| 19 | + |
| 20 | +=pod |
| 21 | + Return dynamic content to the user. |
| 22 | + The content is generated on-line, not from a stored file or a memory buffer. |
| 23 | + Common usage examples: |
| 24 | + Returning the results of a "select * from TABLE" query, without storing the results in a temporary file. |
| 25 | +
|
| 26 | +
|
| 27 | + Couple of technical notes: |
| 28 | + 1. send_file() documentation: |
| 29 | + https://metacpan.org/module/Dancer#send_file |
| 30 | +
|
| 31 | + 2. send_file was originally designed to send either physical files, or in-memory scalars. |
| 32 | + The streaming option was added later - so some hacks are required. |
| 33 | +
|
| 34 | + 3. The "override" callback will take care of all data sent to the user/front-end-HTTP-server, |
| 35 | + and so the first parameter to 'send_file' doesn't matter |
| 36 | + (just needs to be a scalar-ref, otherwise it will be mistaken for a file-name). |
| 37 | +
|
| 38 | + 4. The "$respond" parameter is a PSGI-related opaque object. Use it to generate the 'writer' object. |
| 39 | +
|
| 40 | + 5. The "$response" parameter is the original Dancer::Response object that Dancer generated. |
| 41 | + Can be safely ignored, as we generate our own response. |
| 42 | +
|
| 43 | +=cut |
| 44 | +get '/dynamic_content_download' => sub { |
| 45 | + send_file( |
| 46 | + \"foo", # anything, as long as it's a scalar-ref |
| 47 | + streaming => 1, # enable streaming |
| 48 | + callbacks => { |
| 49 | + override => sub { |
| 50 | + my ( $respond, $response ) = @_; |
| 51 | + |
| 52 | + |
| 53 | + my $http_status_code = 200 ; |
| 54 | + # Tech.note: This is a hash of HTTP header/values, but the |
| 55 | + # function below requires an even-numbered array-ref. |
| 56 | + my @http_headers = ( 'Content-Type' => 'text/plain', |
| 57 | + 'Content-Disposition' => 'attachment; filename="foo.txt"', |
| 58 | + |
| 59 | + # Since this is dynamic content, |
| 60 | + # try hard (with extra HTTP headers) to prevent caching. |
| 61 | + 'Last-Modified' => strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime), |
| 62 | + 'Expires' => 'Tue, 03 Jul 2001 06:00:00 GMT', |
| 63 | + 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0', |
| 64 | + 'Pragma' => 'no-cache' ); |
| 65 | + |
| 66 | + # Send the HTTP headers |
| 67 | + # (back to either the user or the upstream HTTP web-server front-end) |
| 68 | + my $writer = $respond->( [ $http_status_code, \@http_headers ] ); |
| 69 | + |
| 70 | + # Generate a lot of text... |
| 71 | + foreach my $line_number ( 1 .. 1000000 ) { |
| 72 | + $writer->write("Hello World (line $line_number)\n"); |
| 73 | + } |
| 74 | + }, |
| 75 | + }, |
| 76 | + ); |
| 77 | +}; |
| 78 | + |
| 79 | + |
| 80 | +true; |
0 commit comments