Commits

cuerty committed bcfe941

Add: trimming functions, taked as a base, copied from mod_trim (http://www.thrull.com/corner/webserver/mod-trim/).

Comments (0)

Files changed (1)

+/*
+ * Copyright 2010 Angel Freire
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_buckets.h"
+#include "apr_strings.h"
+#include "ap_config.h"
+#include "util_filter.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+static const char minification_filter_name[] = "MINIFICATION";
+
+typedef struct _minification_state {
+    int forbidden;
+    int empty;
+    int content_length;
+} minification_state;
+
+typedef struct {
+    apr_bucket_brigade *bb;
+    minification_state ts;
+} minification_ctx;
+
+int minification(minification_state * s, char *data, int len)
+{
+        int count = 0;
+        int i;
+        char c;
+
+        for (i = 0; i < len; i++) {
+                c = data[i];
+
+                switch (c) {
+                case 13:
+                case 10:
+                case 9:
+                case 32:
+                        if (s->forbidden) {
+                            data[count++] = c;
+                        } else if (!s->empty) {
+                            data[count++] = c;
+                            s->empty = 1;
+                        }
+                        break;
+                case '<':
+                        if (((i + 3 < len) && !strncasecmp(data + i + 1, "pre", 3)) ||
+                             ((i + 8 < len) && !strncasecmp(data + i + 1, "textarea", 8))) {
+                                s->forbidden = 1;
+                        } else if (s->forbidden)
+                                if (((i + 4 < len) && !strncasecmp(data + i + 1, "/pre", 4)) ||
+                                    ((i + 9 < len) && !strncasecmp(data + i + 1, "/textarea", 9))) {
+                                        s->forbidden = 0;
+                                }
+                default:
+                        data[count++] = c;
+                        s->empty = 0;
+                        break;
+                }
+        }
+        data[count] = 0;
+        return count;
+}
+
+static apr_bucket* do_minification(const char *str, size_t len, apr_bucket_alloc_t* alloc, minification_state *ts)
+{
+        char *buffer;
+        apr_bucket* b;
+        buffer = malloc(len + 1);
+        size_t out_size = 0;
+
+        if (!buffer) {
+                return NULL;
+        }
+
+        memcpy(buffer, str, len);
+        out_size = minification(ts, buffer, len);
+        //bucket = apr_bucket_transient_create(buffer, out_size, alloc);
+        b = apr_bucket_heap_create(buffer, out_size, NULL, alloc);
+        free(buffer);
+
+        return b;
+}
+
+static apr_status_t minification_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+{
+    apr_bucket* b;
+    apr_bucket* old;
+    minification_ctx *ctx = f->ctx;
+    const char* buf;
+    size_t bytes;
+
+    if (!ctx)
+    {
+        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+        apr_table_unset(f->r->headers_out, "Content-Length");
+        apr_table_unset(f->r->headers_out, "Content-MD5");
+
+        // init values
+        ctx->ts.forbidden = 0;
+        ctx->ts.empty = 1;
+        ctx->ts.content_length = 0;
+    }
+
+    for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b))
+    {
+        if (APR_BUCKET_IS_EOS(b))
+        {
+            //do nothing at the momment
+        }
+        else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS )
+        {
+            // replace old whole bucket with trimmed one
+            apr_bucket *new = do_minification(buf, bytes, f->r->connection->bucket_alloc, &ctx->ts);
+            old = b;
+            APR_BUCKET_INSERT_BEFORE(b, new);
+            apr_bucket_delete(old);
+            b = new;
+        }
+    }
+    return ap_pass_brigade(f->next, bb);
+}
+
+static void minification_register_hooks(apr_pool_t *p)
+{
+    ap_register_output_filter(minification_filter_name, minification_filter,
+            NULL, AP_FTYPE_RESOURCE);
+}
+
+/* Dispatch list for API hooks */
+
+module AP_MODULE_DECLARE_DATA minification_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,                            /* create per-dir    config structures */
+    NULL,                            /* merge  per-dir    config structures */
+    NULL,                            /* create per-server config structures */
+    NULL,                            /* merge  per-server config structures */
+    NULL,                            /* table of config file commands       */
+    minification_register_hooks      /* register hooks                      */
+};