~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to proxy/http2/remap/RemapProcessor.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
7
  Licensed to the Apache Software Foundation (ASF) under one
 
8
  or more contributor license agreements.  See the NOTICE file
 
9
  distributed with this work for additional information
 
10
  regarding copyright ownership.  The ASF licenses this file
 
11
  to you under the Apache License, Version 2.0 (the
 
12
  "License"); you may not use this file except in compliance
 
13
  with the License.  You may obtain a copy of the License at
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
17
  Unless required by applicable law or agreed to in writing, software
 
18
  distributed under the License is distributed on an "AS IS" BASIS,
 
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
20
  See the License for the specific language governing permissions and
 
21
  limitations under the License.
 
22
 */
 
23
 
 
24
#include "RemapProcessor.h"
 
25
 
 
26
RemapProcessor remapProcessor;
 
27
extern ClassAllocator<RemapPlugins> pluginAllocator;
 
28
 
 
29
int
 
30
RemapProcessor::start(int num_threads)
 
31
{
 
32
  ET_REMAP = eventProcessor.spawn_event_threads(num_threads);  // ET_REMAP is a class member
 
33
  return 0;
 
34
}
 
35
 
 
36
/**
 
37
  Most of this comes from UrlRewrite::Remap(). Generally, all this does
 
38
  is set "map" to the appropriate entry from the global rewrite_table
 
39
  such that we will then have access to the correct url_mapping inside
 
40
  perform_remap.
 
41
 
 
42
*/
 
43
bool
 
44
RemapProcessor::setup_for_remap(HttpTransact::State * s)
 
45
{
 
46
  Debug("url_rewrite", "setting up for remap: %x", s);
 
47
  URL *request_url = NULL;
 
48
  bool mapping_found = false;
 
49
  HTTPHdr *request_header = &s->hdr_info.client_request;
 
50
  char **redirect_url = &s->remap_redirect;
 
51
  char **orig_url = &s->unmapped_request_url;
 
52
  char *tag = NULL;
 
53
  const char *request_host;
 
54
  int request_host_len;
 
55
  int request_port;
 
56
  bool proxy_request = false;
 
57
 
 
58
  s->reverse_proxy = rewrite_table->reverse_proxy;
 
59
  s->url_map.set(s->hdr_info.client_request.m_heap);
 
60
 
 
61
  ink_assert(redirect_url != NULL);
 
62
 
 
63
  if (unlikely(rewrite_table->num_rules_forward == 0)) {
 
64
    ink_assert(rewrite_table->forward_mappings.empty());
 
65
    return false;
 
66
  }
 
67
  // Since we are called before request validity checking
 
68
  // occurs, make sure that we have both a valid request
 
69
  // header and a valid URL
 
70
  if (unlikely(!request_header || (request_url = request_header->url_get()) == NULL || !request_url->valid())) {
 
71
    Error("NULL or invalid request data");
 
72
    return false;
 
73
  }
 
74
 
 
75
  request_host = request_header->host_get(&request_host_len);
 
76
  request_port = request_header->port_get();
 
77
  proxy_request = request_header->is_target_in_url() || ! s->reverse_proxy;
 
78
 
 
79
  // Default to empty host.
 
80
  if (!request_host) {
 
81
    request_host = "";
 
82
    request_host_len = 0;
 
83
  }
 
84
 
 
85
  Debug("url_rewrite", "[lookup] attempting %s lookup", proxy_request ? "proxy" : "normal");
 
86
 
 
87
  mapping_found = rewrite_table->forwardMappingLookup(request_url, request_port, request_host, request_host_len, s->url_map, tag);
 
88
 
 
89
  if (!proxy_request) { // do extra checks on a server request
 
90
 
 
91
    // Save this information for later
 
92
    // @amc: why is this done only for requests without a host in the URL?
 
93
    s->hh_info.host_len = request_host_len;
 
94
    s->hh_info.request_host = request_host;
 
95
    s->hh_info.request_port = request_port;
 
96
 
 
97
    // If no rules match and we have a host, check empty host rules since
 
98
    // they function as default rules for server requests.
 
99
    // If there's no host, we've already done this.
 
100
    if (!mapping_found && rewrite_table->nohost_rules && request_host_len) {
 
101
      Debug("url_rewrite", "[lookup] nothing matched");
 
102
      mapping_found = rewrite_table->forwardMappingLookup(request_url, 0, "", 0, s->url_map, tag);
 
103
    }
 
104
 
 
105
    if (mapping_found && orig_url) {
 
106
      // Downstream mapping logic (e.g., self::finish_remap())
 
107
      // apparently assumes the presence of the target in the URL, so
 
108
      // we need to copy it. Perhaps it's because it's simpler to just
 
109
      // do the remap on the URL and then fix the field at the end.
 
110
      request_header->set_url_target_from_host_field();
 
111
      *orig_url = request_url->string_get_ref(NULL);
 
112
    }
 
113
  }
 
114
 
 
115
  if (mapping_found) {
 
116
    request_header->mark_target_dirty();
 
117
  } else {
 
118
    Debug("url_rewrite", "RemapProcessor::setup_for_remap did not find a mapping");
 
119
  }
 
120
 
 
121
  return mapping_found;
 
122
}
 
123
 
 
124
bool
 
125
RemapProcessor::finish_remap(HttpTransact::State * s)
 
126
{
 
127
  url_mapping *map = NULL;
 
128
  HTTPHdr *request_header = &s->hdr_info.client_request;
 
129
  URL *request_url = request_header->url_get();
 
130
  char **orig_url = &s->unmapped_request_url;
 
131
  char **redirect_url = &s->remap_redirect;
 
132
  const int host_buf_len = MAXDNAME + 12 + 1 + 1;
 
133
  char host_hdr_buf[host_buf_len], tmp_referer_buf[4096], tmp_redirect_buf[4096], tmp_buf[2048], *c;
 
134
  const char *remapped_host;
 
135
  int remapped_host_len, remapped_port, tmp;
 
136
  int from_len;
 
137
  bool remap_found = false;
 
138
  referer_info *ri;
 
139
 
 
140
  map = s->url_map.getMapping();
 
141
  if (!map) {
 
142
    return false;
 
143
  }
 
144
  // Do fast ACL filtering (it is safe to check map here)
 
145
  rewrite_table->PerformACLFiltering(s, map);
 
146
 
 
147
  // Check referer filtering rules
 
148
  if ((s->filter_mask & URL_REMAP_FILTER_REFERER) != 0 && (ri = map->referer_list) != 0) {
 
149
    const char *referer_hdr = 0;
 
150
    int referer_len = 0;
 
151
    bool enabled_flag = map->optional_referer ? true : false;
 
152
 
 
153
    if (request_header->presence(MIME_PRESENCE_REFERER) &&
 
154
        (referer_hdr = request_header->value_get(MIME_FIELD_REFERER, MIME_LEN_REFERER, &referer_len)) != NULL) {
 
155
      if (referer_len >= (int) sizeof(tmp_referer_buf))
 
156
        referer_len = (int) (sizeof(tmp_referer_buf) - 1);
 
157
      memcpy(tmp_referer_buf, referer_hdr, referer_len);
 
158
      tmp_referer_buf[referer_len] = 0;
 
159
      for (enabled_flag = false; ri; ri = ri->next) {
 
160
        if (ri->any) {
 
161
          enabled_flag = true;
 
162
          if (!map->negative_referer)
 
163
            break;
 
164
        } else if (ri->regx_valid && (pcre_exec(ri->regx, NULL, tmp_referer_buf, referer_len, 0, 0, NULL, 0) != -1)) {
 
165
          enabled_flag = ri->negative ? false : true;
 
166
          break;
 
167
        }
 
168
      }
 
169
    }
 
170
 
 
171
    if (!enabled_flag) {
 
172
      if (!map->default_redirect_url) {
 
173
        if ((s->filter_mask & URL_REMAP_FILTER_REDIRECT_FMT) != 0 && map->redir_chunk_list) {
 
174
          redirect_tag_str *rc;
 
175
          tmp_redirect_buf[(tmp = 0)] = 0;
 
176
          for (rc = map->redir_chunk_list; rc; rc = rc->next) {
 
177
            c = 0;
 
178
            switch (rc->type) {
 
179
            case 's':
 
180
              c = rc->chunk_str;
 
181
              break;
 
182
            case 'r':
 
183
              c = (referer_len && referer_hdr) ? &tmp_referer_buf[0] : 0;
 
184
              break;
 
185
            case 'f':
 
186
            case 't':
 
187
              remapped_host =
 
188
                (rc->type == 'f') ? map->fromURL.string_get_buf(tmp_buf, (int) sizeof(tmp_buf),
 
189
                                                                &from_len) : ((s->url_map).getToURL())->string_get_buf(tmp_buf, (int)
 
190
                                                                                                       sizeof(tmp_buf),
 
191
                                                                                                       &from_len);
 
192
              if (remapped_host && from_len > 0) {
 
193
                c = &tmp_buf[0];
 
194
              }
 
195
              break;
 
196
            case 'o':
 
197
              c = *orig_url;
 
198
              break;
 
199
            };
 
200
 
 
201
            if (c && tmp < (int) (sizeof(tmp_redirect_buf) - 1)) {
 
202
              tmp += snprintf(&tmp_redirect_buf[tmp], sizeof(tmp_redirect_buf) - tmp, "%s", c);
 
203
            }
 
204
          }
 
205
          tmp_redirect_buf[sizeof(tmp_redirect_buf) - 1] = 0;
 
206
          *redirect_url = xstrdup(tmp_redirect_buf);
 
207
        }
 
208
      } else {
 
209
        *redirect_url = xstrdup(rewrite_table->http_default_redirect_url);
 
210
      }
 
211
 
 
212
      if (*redirect_url == NULL) {
 
213
        *redirect_url =
 
214
          xstrdup(map->filter_redirect_url ? map->filter_redirect_url : rewrite_table->http_default_redirect_url);
 
215
      }
 
216
 
 
217
      return false;
 
218
    }
 
219
  }
 
220
 
 
221
  remap_found = true;
 
222
 
 
223
  // We also need to rewrite the "Host:" header if it exists and
 
224
  //   pristine host hdr is not enabled
 
225
  int host_len;
 
226
  const char *host_hdr = request_header->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_len);
 
227
 
 
228
  if (request_url && host_hdr != NULL && s->txn_conf.maintain_pristine_host_hdr == 0) {
 
229
    remapped_host = request_url->host_get(&remapped_host_len);
 
230
    remapped_port = request_url->port_get_raw();
 
231
 
 
232
    // Debug code to print out old host header.  This was easier before
 
233
    //  the header conversion.  Now we have to copy to gain null
 
234
    //  termination for the Debug() call
 
235
    if (is_debug_tag_set("url_rewrite")) {
 
236
      int old_host_hdr_len;
 
237
      char *old_host_hdr = (char *) request_header->value_get(MIME_FIELD_HOST,
 
238
                                                              MIME_LEN_HOST,
 
239
                                                              &old_host_hdr_len);
 
240
      if (old_host_hdr) {
 
241
        old_host_hdr = xstrndup(old_host_hdr, old_host_hdr_len);
 
242
        Debug("url_rewrite", "Host: Header before rewrite %.*s", old_host_hdr_len, old_host_hdr);
 
243
        xfree(old_host_hdr);
 
244
      }
 
245
    }
 
246
    //
 
247
    // Create the new host header field being careful that our
 
248
    //   temporary buffer has adequate length
 
249
    //
 
250
    if (host_buf_len > remapped_host_len) {
 
251
      tmp = remapped_host_len;
 
252
      memcpy(host_hdr_buf, remapped_host, remapped_host_len);
 
253
      if (remapped_port) {
 
254
        tmp += snprintf(host_hdr_buf + remapped_host_len, host_buf_len - remapped_host_len - 1, ":%d", remapped_port);
 
255
    }
 
256
    } else {
 
257
      tmp = host_buf_len;
 
258
    }
 
259
 
 
260
    // It is possible that the hostname is too long.  If it is punt,
 
261
    //   and remove the host header.  If it is too long the HostDB
 
262
    //   won't be able to resolve it and the request will not go
 
263
    //   through
 
264
    if (tmp >= host_buf_len) {
 
265
      request_header->field_delete(MIME_FIELD_HOST, MIME_LEN_HOST);
 
266
      Debug("url_rewrite", "Host: Header too long after rewrite");
 
267
    } else {
 
268
      Debug("url_rewrite", "Host: Header after rewrite %.*s", tmp, host_hdr_buf);
 
269
      request_header->value_set(MIME_FIELD_HOST, MIME_LEN_HOST, host_hdr_buf, tmp);
 
270
    }
 
271
  }
 
272
 
 
273
  return remap_found;
 
274
}
 
275
 
 
276
Action *
 
277
RemapProcessor::perform_remap(Continuation * cont, HttpTransact::State * s)
 
278
{
 
279
  Debug("url_rewrite", "Beginning RemapProcessor::perform_remap");
 
280
  HTTPHdr *request_header = &s->hdr_info.client_request;
 
281
  URL *request_url = request_header->url_get();
 
282
  url_mapping *map = s->url_map.getMapping();
 
283
  host_hdr_info *hh_info = &(s->hh_info);
 
284
 
 
285
  if (!map) {
 
286
    Error("Could not find corresponding url_mapping for this transaction %x", s);
 
287
    Debug("url_rewrite", "Could not find corresponding url_mapping for this transaction");
 
288
    ink_debug_assert(!"this should never happen -- call setup_for_remap first");
 
289
    cont->handleEvent(EVENT_REMAP_ERROR, NULL);
 
290
    return ACTION_RESULT_DONE;
 
291
  }
 
292
 
 
293
  // EThread *t = cont->mutex->thread_holding;
 
294
  // RemapPlugins *plugins = THREAD_ALLOC_INIT(pluginAllocator, t);
 
295
 
 
296
  RemapPlugins *plugins = pluginAllocator.alloc();
 
297
 
 
298
  plugins->setMap(&(s->url_map));
 
299
  plugins->setRequestUrl(request_url);
 
300
  plugins->setRequestHeader(request_header);
 
301
  plugins->setState(s);
 
302
  plugins->setHostHeaderInfo(hh_info);
 
303
 
 
304
  if (!_use_separate_remap_thread) {    // lets not schedule anything on our thread group (ET_REMAP), instead, just execute inline
 
305
    int ret = 0;
 
306
    do {
 
307
      ret = plugins->run_single_remap();
 
308
    } while (ret == 0);
 
309
    //THREAD_FREE(plugins, pluginAllocator, t);
 
310
    pluginAllocator.free(plugins);
 
311
    return ACTION_RESULT_DONE;
 
312
  } else {
 
313
    ink_debug_assert(cont->mutex->thread_holding == this_ethread());
 
314
    plugins->mutex = cont->mutex;
 
315
    plugins->action = cont;
 
316
    SET_CONTINUATION_HANDLER(plugins, &RemapPlugins::run_remap);
 
317
    eventProcessor.schedule_imm(plugins, ET_REMAP);
 
318
    return &plugins->action;
 
319
  }
 
320
}