~ubuntu-branches/ubuntu/trusty/mapcache/trusty

« back to all changes in this revision

Viewing changes to nginx/ngx_http_mapcache_module.c

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2013-09-11 19:16:06 UTC
  • Revision ID: package-import@ubuntu.com-20130911191606-9aydo919w4dgjx9v
Tags: upstream-1.2.0
ImportĀ upstreamĀ versionĀ 1.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <ngx_config.h>
 
2
#include <ngx_core.h>
 
3
#include <ngx_http.h>
 
4
#include "../include/mapcache.h"
 
5
#include <apr_date.h>
 
6
#include <apr_strings.h>
 
7
#include <apr_pools.h>
 
8
 
 
9
 
 
10
apr_pool_t *process_pool = NULL;
 
11
static char *ngx_http_mapcache(ngx_conf_t *cf, ngx_command_t *cmd,
 
12
                               void *conf);
 
13
 
 
14
static ngx_command_t  ngx_http_mapcache_commands[] = {
 
15
 
 
16
  {
 
17
    ngx_string("mapcache"),
 
18
    NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 
19
    ngx_http_mapcache,
 
20
    NGX_HTTP_LOC_CONF_OFFSET,
 
21
    0,
 
22
    NULL
 
23
  },
 
24
 
 
25
  ngx_null_command
 
26
};
 
27
 
 
28
typedef struct {
 
29
  mapcache_context ctx;
 
30
  ngx_http_request_t *r;
 
31
} mapcache_ngx_context;
 
32
 
 
33
static void ngx_mapcache_context_log(mapcache_context *c, mapcache_log_level level, char *message, ...)
 
34
{
 
35
  mapcache_ngx_context *ctx = (mapcache_ngx_context*)c;
 
36
  va_list args;
 
37
  if(!c->config || level >= c->config->loglevel) {
 
38
    va_start(args,message);
 
39
    ngx_log_error(NGX_LOG_ALERT, ctx->r->connection->log, 0,
 
40
                  apr_pvsprintf(c->pool,message,args));
 
41
    va_end(args);
 
42
  }
 
43
}
 
44
 
 
45
static mapcache_context* ngx_mapcache_context_clone(mapcache_context *ctx)
 
46
{
 
47
  mapcache_context *nctx = (mapcache_context*)apr_pcalloc(ctx->pool,
 
48
                           sizeof(mapcache_ngx_context));
 
49
  mapcache_context_copy(ctx,nctx);
 
50
  ((mapcache_ngx_context*)nctx)->r = ((mapcache_ngx_context*)ctx)->r;
 
51
  apr_pool_create(&nctx->pool,ctx->pool);
 
52
  return nctx;
 
53
}
 
54
 
 
55
 
 
56
static void *
 
57
ngx_http_mapcache_create_conf(ngx_conf_t *cf)
 
58
{
 
59
  apr_initialize();
 
60
  atexit(apr_terminate);
 
61
  apr_pool_initialize();
 
62
  apr_pool_create(&process_pool,NULL);
 
63
  mapcache_context *ctx = apr_pcalloc(process_pool, sizeof(mapcache_ngx_context));
 
64
  ctx->pool = process_pool;
 
65
  ctx->process_pool = process_pool;
 
66
  ctx->threadlock = NULL;
 
67
  mapcache_context_init(ctx);
 
68
  ctx->log = ngx_mapcache_context_log;
 
69
  ctx->clone = ngx_mapcache_context_clone;
 
70
  ctx->config = NULL;
 
71
 
 
72
 
 
73
  return ctx;
 
74
}
 
75
 
 
76
 
 
77
static void ngx_http_mapcache_write_response(mapcache_context *ctx, ngx_http_request_t *r,
 
78
    mapcache_http_response *response)
 
79
{
 
80
  if(response->mtime) {
 
81
    time_t  if_modified_since;
 
82
    if(r->headers_in.if_modified_since) {
 
83
      if_modified_since = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
 
84
                                              r->headers_in.if_modified_since->value.len);
 
85
      if (if_modified_since != NGX_ERROR) {
 
86
        apr_time_t apr_if_m_s;
 
87
        apr_time_ansi_put ( &apr_if_m_s, if_modified_since);
 
88
        if(apr_if_m_s<response->mtime) {
 
89
          r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
 
90
          ngx_http_send_header(r);
 
91
          return;
 
92
        }
 
93
      }
 
94
    }
 
95
    char *datestr;
 
96
    datestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
 
97
    apr_rfc822_date(datestr, response->mtime);
 
98
    apr_table_setn(response->headers,"Last-Modified",datestr);
 
99
  }
 
100
  if(response->headers && !apr_is_empty_table(response->headers)) {
 
101
    const apr_array_header_t *elts = apr_table_elts(response->headers);
 
102
    int i;
 
103
    for(i=0; i<elts->nelts; i++) {
 
104
      apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t);
 
105
      if(!strcasecmp(entry.key,"Content-Type")) {
 
106
        r->headers_out.content_type.len = strlen(entry.val);
 
107
        r->headers_out.content_type.data = (u_char*)entry.val;
 
108
      } else {
 
109
        ngx_table_elt_t   *h;
 
110
        h = ngx_list_push(&r->headers_out.headers);
 
111
        if (h == NULL) {
 
112
          return;
 
113
        }
 
114
        h->key.len = strlen(entry.key) ;
 
115
        h->key.data = (u_char*)entry.key ;
 
116
        h->value.len = strlen(entry.val) ;
 
117
        h->value.data = (u_char*)entry.val ;
 
118
        h->hash = 1;
 
119
      }
 
120
    }
 
121
  }
 
122
  if(response->data) {
 
123
    r->headers_out.content_length_n = response->data->size;
 
124
  }
 
125
  int rc;
 
126
  r->headers_out.status = response->code;
 
127
  rc = ngx_http_send_header(r);
 
128
  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
 
129
    return;
 
130
  }
 
131
 
 
132
  if(response->data) {
 
133
    ngx_buf_t    *b;
 
134
    ngx_chain_t   out;
 
135
    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
 
136
    if (b == NULL) {
 
137
      ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
 
138
                    "Failed to allocate response buffer.");
 
139
      return;
 
140
    }
 
141
 
 
142
    b->pos = ngx_pcalloc(r->pool,response->data->size);
 
143
    memcpy(b->pos,response->data->buf,response->data->size);
 
144
    b->last = b->pos + response->data->size;
 
145
    b->memory = 1;
 
146
    b->last_buf = 1;
 
147
    b->flush = 1;
 
148
    out.buf = b;
 
149
    out.next = NULL;
 
150
    ngx_http_output_filter(r, &out);
 
151
  }
 
152
 
 
153
}
 
154
 
 
155
 
 
156
static ngx_http_module_t  ngx_http_mapcache_module_ctx = {
 
157
  NULL,                          /* preconfiguration */
 
158
  NULL,                          /* postconfiguration */
 
159
 
 
160
  NULL,                          /* create main configuration */
 
161
  NULL,                          /* init main configuration */
 
162
 
 
163
  NULL,                          /* create server configuration */
 
164
  NULL,                          /* merge server configuration */
 
165
 
 
166
  ngx_http_mapcache_create_conf, /* create location configuration */
 
167
  NULL                           /* merge location configuration */
 
168
};
 
169
 
 
170
static ngx_int_t ngx_mapcache_init_process(ngx_cycle_t *cycle)
 
171
{
 
172
  apr_initialize();
 
173
  atexit(apr_terminate);
 
174
  apr_pool_initialize();
 
175
  apr_pool_create(&process_pool,NULL);
 
176
  return NGX_OK;
 
177
}
 
178
 
 
179
static void ngx_mapcache_exit_process(ngx_cycle_t *cycle)
 
180
{
 
181
  apr_pool_destroy(process_pool);
 
182
}
 
183
 
 
184
ngx_module_t  ngx_http_mapcache_module = {
 
185
  NGX_MODULE_V1,
 
186
  &ngx_http_mapcache_module_ctx, /* module context */
 
187
  ngx_http_mapcache_commands,   /* module directives */
 
188
  NGX_HTTP_MODULE,               /* module type */
 
189
  NULL,                          /* init master */
 
190
  NULL,                          /* init module */
 
191
  ngx_mapcache_init_process,/* init process */
 
192
  NULL,                          /* init thread */
 
193
  NULL,                          /* exit thread */
 
194
  ngx_mapcache_exit_process,                          /* exit process */
 
195
  ngx_mapcache_exit_process,                          /* exit master */
 
196
  NGX_MODULE_V1_PADDING
 
197
};
 
198
 
 
199
static ngx_str_t  pathinfo_str = ngx_string("path_info");
 
200
static ngx_int_t pathinfo_index;
 
201
static ngx_str_t  urlprefix_str = ngx_string("url_prefix");
 
202
static ngx_int_t urlprefix_index;
 
203
 
 
204
static ngx_int_t
 
205
ngx_http_mapcache_handler(ngx_http_request_t *r)
 
206
{
 
207
  int ret = NGX_HTTP_OK;
 
208
  if (!(r->method & (NGX_HTTP_GET))) {
 
209
    return NGX_HTTP_NOT_ALLOWED;
 
210
  }
 
211
  mapcache_ngx_context *ngctx = ngx_http_get_module_loc_conf(r, ngx_http_mapcache_module);
 
212
  mapcache_context *ctx = (mapcache_context*)ngctx;
 
213
  apr_pool_create(&(ctx->pool),process_pool);
 
214
  ctx->process_pool = process_pool;
 
215
  ngctx->r = r;
 
216
  mapcache_request *request = NULL;
 
217
  mapcache_http_response *http_response;
 
218
 
 
219
  ngx_http_variable_value_t      *pathinfovv = ngx_http_get_indexed_variable(r, pathinfo_index);
 
220
 
 
221
  char* pathInfo = apr_pstrndup(ctx->pool, (char*)pathinfovv->data, pathinfovv->len);
 
222
  char *sparams = apr_pstrndup(ctx->pool, (char*)r->args.data, r->args.len);
 
223
  apr_table_t *params = mapcache_http_parse_param_string(ctx, sparams);
 
224
 
 
225
  mapcache_service_dispatch_request(ctx,&request,pathInfo,params,ctx->config);
 
226
  if(GC_HAS_ERROR(ctx) || !request) {
 
227
    ngx_http_mapcache_write_response(ctx,r, mapcache_core_respond_to_error(ctx));
 
228
    goto cleanup;
 
229
  }
 
230
 
 
231
  http_response = NULL;
 
232
  if(request->type == MAPCACHE_REQUEST_GET_CAPABILITIES) {
 
233
    mapcache_request_get_capabilities *req = (mapcache_request_get_capabilities*)request;
 
234
    ngx_http_variable_value_t      *urlprefixvv = ngx_http_get_indexed_variable(r, urlprefix_index);
 
235
    char *url = apr_pstrcat(ctx->pool,
 
236
                            "http://",
 
237
                            apr_pstrndup(ctx->pool, (char*)r->headers_in.host->value.data, r->headers_in.host->value.len),
 
238
                            apr_pstrndup(ctx->pool, (char*)urlprefixvv->data, urlprefixvv->len),
 
239
                            "/",
 
240
                            NULL
 
241
                           );
 
242
    http_response = mapcache_core_get_capabilities(ctx,request->service,req,url,pathInfo,ctx->config);
 
243
  } else if( request->type == MAPCACHE_REQUEST_GET_TILE) {
 
244
    mapcache_request_get_tile *req_tile = (mapcache_request_get_tile*)request;
 
245
    http_response = mapcache_core_get_tile(ctx,req_tile);
 
246
  } else if( request->type == MAPCACHE_REQUEST_GET_MAP) {
 
247
    mapcache_request_get_map *req_map = (mapcache_request_get_map*)request;
 
248
    http_response = mapcache_core_get_map(ctx,req_map);
 
249
#ifdef NGINX_RW
 
250
  } else if( request->type == MAPCACHE_REQUEST_PROXY ) {
 
251
    mapcache_request_proxy *req_proxy = (mapcache_request_proxy*)request;
 
252
    http_response = mapcache_core_proxy_request(ctx, req_proxy);
 
253
  } else if( request->type == MAPCACHE_REQUEST_GET_FEATUREINFO) {
 
254
    mapcache_request_get_feature_info *req_fi = (mapcache_request_get_feature_info*)request;
 
255
    http_response = mapcache_core_get_featureinfo(ctx,req_fi);
 
256
#endif
 
257
#ifdef DEBUG
 
258
  } else {
 
259
    ctx->set_error(ctx,500,"###BUG### unknown request type");
 
260
#endif
 
261
  }
 
262
  if(GC_HAS_ERROR(ctx)) {
 
263
    //   ngx_http_mapcache_write_response(ctx,r, mapcache_core_respond_to_error(ctx));
 
264
    goto cleanup;
 
265
  }
 
266
#ifdef DEBUG
 
267
  if(!http_response) {
 
268
    ctx->set_error(ctx,500,"###BUG### NULL response");
 
269
    ngx_http_mapcache_write_response(ctx,r, mapcache_core_respond_to_error(ctx));
 
270
    goto cleanup;
 
271
  }
 
272
#endif
 
273
  ngx_http_mapcache_write_response(ctx,r,http_response);
 
274
cleanup:
 
275
  if(GC_HAS_ERROR(ctx))
 
276
    ret = ctx->_errcode?ctx->_errcode:500;
 
277
  ctx->clear_errors(ctx);
 
278
  apr_pool_destroy(ctx->pool);
 
279
  return ret;
 
280
}
 
281
 
 
282
 
 
283
static char *
 
284
ngx_http_mapcache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
285
{
 
286
  mapcache_context *ctx = conf;
 
287
  ngx_str_t *value;
 
288
  value = cf->args->elts;
 
289
  char *conffile = (char*)value[1].data;
 
290
  ctx->config = mapcache_configuration_create(ctx->pool);
 
291
  mapcache_configuration_parse(ctx,conffile,ctx->config,1);
 
292
  if(GC_HAS_ERROR(ctx)) {
 
293
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,ctx->get_error_message(ctx));
 
294
    return NGX_CONF_ERROR;
 
295
  }
 
296
  mapcache_configuration_post_config(ctx, ctx->config);
 
297
  if(GC_HAS_ERROR(ctx)) {
 
298
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,ctx->get_error_message(ctx));
 
299
    return NGX_CONF_ERROR;
 
300
  }
 
301
  ctx->config->non_blocking = 1;
 
302
 
 
303
  ngx_http_core_loc_conf_t  *clcf;
 
304
 
 
305
  clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 
306
  clcf->handler = ngx_http_mapcache_handler;
 
307
 
 
308
  pathinfo_index = ngx_http_get_variable_index(cf, &pathinfo_str);
 
309
  if (pathinfo_index == NGX_ERROR) {
 
310
    return NGX_CONF_ERROR;
 
311
  }
 
312
  urlprefix_index = ngx_http_get_variable_index(cf, &urlprefix_str);
 
313
  if (urlprefix_index == NGX_ERROR) {
 
314
    return NGX_CONF_ERROR;
 
315
  }
 
316
 
 
317
  return NGX_CONF_OK;
 
318
}