Вопрос по com.sun.net.httpserver.*

 
 
 
Сообщения:2
Здравствуйте!
Есть задача по написанию простого веб сервера с авторизацией по NTLM, чтобы получить автоматом логин пользователя.
Реализовать удалось, но происходит зависание, из-за которого открытие странички в браузере занимает около 30 сек.
В самом низу пример кода, в котором воспроизводится зависание.
Код не идеальный, можно и лучше, но я только учусь, поэтому попрошу "ссаными тряпками" не кидаться, а помочь разобраться в проблеме. )
Заранее благодарю.

Общая схема:
1. Браузер запрашивает страницу.
2. Я ему в ответ:
//говорю, какой тип авторизации
headers.add("WWW-Authenticate", "NTLM");
//Код ответа и длинна тела запроса
exchange.sendResponseHeaders(401, bytes.length);

3. Браузер мне присылает строку типа:
Authorization: NTLM TlRMzVNTUAABJAAAg7IIogQZBAAwAAdACZAIACgAAdAGAAEdAA0AD0lZUFJCRzM3AkzOSw==

4. Я ему в ответ(после этого этапа предположительно происходит зависание):
headers.add("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAAAICAgAAAAAAAAAAAAAAAA==");
exchange.sendResponseHeaders(401, bytes.length);

5. После ожидания браузер присылает "Authorization" с логином пользователя, доменом и именем ПК.
6. После получения логина, сервер отправляет целевую страницу.

На сколько удалось проследить, зависание происходит именно в httpserver, т.к. на стадии выполнения программы мной написанного кода зависаний нет, отрабатывает от и до за мгновение.

Что удалось обнаружить при помощи программы Fiddler:
После того, как браузер присылает первый "Authorization":
GET http://localhost:83/ HTTP/1.1
Host: localhost:83
Connection: keep-alive
Cache-Control: max-age=0
Authorization: NTLM TlRMzVNTUAABJAAAg7IIogQZBAAwAAdACZAIACgAAdAGAAEdAA0AD0lZUFJCRzM3AkzOSw==
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4


Мой сервер отправляет сначала эту часть заголовка, и на нее я повлиять никак не могу.:
HTTP/1.1 401 Unauthorized
Connection: Keep-Alive
Www-authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAAAICAgAAAAAAAAAAAAAAAA==
Transfer-Encoding: chunked
Proxy-Support: Session-Based-Authentication// Это строка последняя, началось зависание


Потом зависание на ~30 сек и досылается остальная часть заголовка, которую я по коду добавлял перед headers.add("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAAAICAgAAAAAAAAAAAAAAAA==");
Причем по какой-то причине в заголовке есть строка "cd"(эти две буквы меняются), которой быть не должно, и в конце "0":
cd
Keep-alive: timeout=5, max=93
Date: Fri, 06 Jul 2018 12:41:06 GMT
Transfer-encoding: unchunked
Proxy-support: Session-Based-Authentication
Content-type: text/html; charset=utf-8
Content-length: 0


0



Проблемный заголовок целиком:
HTTP/1.1 401 Unauthorized
Connection: Keep-Alive
Www-authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAAAICAgAAAAAAAAAAAAAAAA==
Transfer-Encoding: chunked
Proxy-Support: Session-Based-Authentication //После этой строки зависание около 30 сек

cd
Keep-alive: timeout=5, max=93
Date: Fri, 06 Jul 2018 12:41:06 GMT
Transfer-encoding: unchunked
Proxy-support: Session-Based-Authentication
Content-type: text/html; charset=utf-8
Content-length: 0


0




Листинг сервера(упрощенный, только для понимания, что я делаю в рамках поднимаемого вопроса)
package easyserver;
import com.sun.net.httpserver.*;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import java.util.logging.Logger;

public class EasyServer {


    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create();
        server.bind(new InetSocketAddress(83), 0);
        HttpContext context = server.createContext("/", new EchoHandler());
        context.setAuthenticator(new Auth());
        server.setExecutor(null);
        server.start();
    }
    static class EchoHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            
            StringBuilder builder = new StringBuilder();
            builder.append("<h1>URI: ").append(exchange.getRequestURI()).append("</h1>");
            Headers headers = exchange.getRequestHeaders();
            
            byte[] bytes = builder.toString().getBytes();
            exchange.sendResponseHeaders(200, bytes.length);
            OutputStream os = exchange.getResponseBody();
            os.write(bytes);
            os.close();
        }
        
    }

    static class Auth extends Authenticator {
        @Override
        public Result authenticate(HttpExchange httpExchange) {
            
            Headers headers = httpExchange.getRequestHeaders();
            String auth = "";
            
            Headers respHead = httpExchange.getResponseHeaders();
            String d, m = "", u = "";
            String NTLM = "";
            int i = 200;
            for (String header : headers.keySet()) {
                if (header.equalsIgnoreCase("Authorization") && headers.getFirst(header).startsWith("NTLM ")) {
                    auth = headers.getFirst(header);
                }
            }
            try {
                if (auth.startsWith("NTLM ")) {
                    byte[] msg;
                    msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
                    int off = 0, length, offset;
                    if (msg[8] == 1) {
                        off = 18;
                        byte z = 0;
                        byte[] msg1 = {(byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', (byte) 'S', (byte) 'S', (byte) 'P', z, (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z, (byte) 1, (byte) 130, z, z, z, (byte) 2, (byte) 2, (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z};
                        respHead.add("Connection", "Keep-Alive");
                        respHead.add("Keep-Alive", "timeout=5, max=93");
                        respHead.add("Proxy-Support", "Session-Based-Authentication");
                        respHead.add("Transfer-Encoding", "unchunked");
                        respHead.add("Content-Type", "text/html; charset=utf-8");
                        NTLM = "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1);
                    } else if (msg[8] == 3) {
                        
                        off = 30;
                        length = msg[off + 17] * 256 + msg[off + 16];
                        offset = msg[off + 19] * 256 + msg[off + 18];
                        m = new String(msg, offset, length);
                        length = msg[off + 1] * 256 + msg[off];
                        offset = msg[off + 3] * 256 + msg[off + 2];
                        d = new String(msg, offset, length);
                        length = msg[off + 9] * 256 + msg[off + 8];
                        offset = msg[off + 11] * 256 + msg[off + 10];
                        u = new String(msg, offset, length);
                        System.out.println("User: " + u);
                    } 
                } else {
                    NTLM = "NTLM";
                }
                
            } catch (IOException ex) {
                Logger.getLogger(EasyServer.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            if (u.equals("")){
                respHead.add("WWW-Authenticate", NTLM);
                System.out.println(u);
                return new Retry(401);
            }
            if (!"/".equals(httpExchange.getRequestURI().toString())) {
                return new Failure(403);
            } else {
                return new Success(new HttpPrincipal("c0nst", "realm"));
            }
        }
    } 
}
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет