Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 40f405d4a28ad877c90cbd6742ae57b4c3a567e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//
//  ========================================================================
//  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//


package org.eclipse.jetty.spdy.server.http;

import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory implements HttpConfiguration.ConnectionFactory
{
    private static final String CHANNEL_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.HTTPChannelOverSPDY";
    private static final Logger LOG = Log.getLogger(HTTPSPDYServerConnectionFactory.class);

    private final PushStrategy pushStrategy;
    private final HttpConfiguration httpConfiguration;

    public HTTPSPDYServerConnectionFactory(
        @Name("version") int version,
        @Name("config") HttpConfiguration config)
    {
        this(version,config,new PushStrategy.None());
    }

    public HTTPSPDYServerConnectionFactory(
        @Name("version") int version,
        @Name("config") HttpConfiguration config,
        @Name("pushStrategy") PushStrategy pushStrategy)
    {
        super(version);
        this.pushStrategy = pushStrategy;
        httpConfiguration = config;
        addBean(httpConfiguration);
    }

    @Override
    public HttpConfiguration getHttpConfiguration()
    {
        return httpConfiguration;
    }

    @Override
    protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
    {
        return new HTTPServerFrameListener(connector,endPoint);
    }

    private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener
    {
        private final Connector connector;
        private final EndPoint endPoint;

        public HTTPServerFrameListener(Connector connector,EndPoint endPoint)
        {
            this.endPoint = endPoint;
            this.connector=connector;
        }

        @Override
        public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
        {
            // Every time we have a SYN, it maps to a HTTP request.
            // We can have multiple concurrent SYNs on the same connection,
            // and this is very different from HTTP, where only one request
            // can arrive on the same connection, so we need to create an
            // HttpChannel for each SYN in order to run concurrently.

            LOG.debug("Received {} on {}", synInfo, stream);

            Fields headers = synInfo.getHeaders();
            // According to SPDY/3 spec section 3.2.1 user-agents MUST support gzip compression. Firefox omits the
            // accept-encoding header as it is redundant to negotiate gzip compression support with the server,
            // if clients have to accept it.
            // So we inject the accept-encoding header here, even if not set by the client. This will enforce SPDY
            // clients to follow the spec and enable gzip compression if GzipFilter or the like is enabled.
            if (!(headers.get("accept-encoding") != null && headers.get("accept-encoding").value().contains
                    ("gzip")))
                headers.add("accept-encoding", "gzip");
            HttpTransportOverSPDY transport = new HttpTransportOverSPDY(connector, httpConfiguration, endPoint,
                    pushStrategy, stream, headers);
            HttpInputOverSPDY input = new HttpInputOverSPDY();
            HttpChannelOverSPDY channel = new HttpChannelOverSPDY(connector, httpConfiguration, endPoint, transport, input, stream);
            stream.setAttribute(CHANNEL_ATTRIBUTE, channel);

            channel.requestStart(headers, synInfo.isClose());

            if (headers.isEmpty())
            {
                // If the SYN has no headers, they may come later in a HEADERS frame
                return this;
            }
            else
            {
                if (synInfo.isClose())
                    return null;
                else
                    return this;
            }
        }

        @Override
        public void onReply(Stream stream, ReplyInfo replyInfo)
        {
            // Do nothing, servers cannot get replies
        }

        @Override
        public void onHeaders(Stream stream, HeadersInfo headersInfo)
        {
            LOG.debug("Received {} on {}", headersInfo, stream);
            HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
            channel.requestHeaders(headersInfo.getHeaders(), headersInfo.isClose());
        }

        @Override
        public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
        {
            return null;
        }

        @Override
        public void onData(Stream stream, final DataInfo dataInfo)
        {
            LOG.debug("Received {} on {}", dataInfo, stream);
            HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
            channel.requestContent(dataInfo, dataInfo.isClose());
        }

        @Override
        public void onFailure(Throwable x)
        {
            LOG.debug(x);
        }
    }
}

Back to the top