1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.ajp;
20
21 import java.io.IOException;
22 import java.io.UnsupportedEncodingException;
23 import java.util.HashMap;
24
25 import org.eclipse.jetty.http.AbstractGenerator;
26 import org.eclipse.jetty.http.HttpFields;
27 import org.eclipse.jetty.http.HttpGenerator;
28 import org.eclipse.jetty.http.HttpTokens;
29 import org.eclipse.jetty.http.HttpVersions;
30 import org.eclipse.jetty.io.Buffer;
31 import org.eclipse.jetty.io.Buffers;
32 import org.eclipse.jetty.io.ByteArrayBuffer;
33 import org.eclipse.jetty.io.EndPoint;
34 import org.eclipse.jetty.io.EofException;
35 import org.eclipse.jetty.util.StringUtil;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38
39
40
41
42
43 public class Ajp13Generator extends AbstractGenerator
44 {
45 private static final Logger LOG = Log.getLogger(Ajp13Generator.class);
46
47 private static HashMap __headerHash = new HashMap();
48
49 static
50 {
51 byte[] xA001 =
52 { (byte)0xA0, (byte)0x01 };
53 byte[] xA002 =
54 { (byte)0xA0, (byte)0x02 };
55 byte[] xA003 =
56 { (byte)0xA0, (byte)0x03 };
57 byte[] xA004 =
58 { (byte)0xA0, (byte)0x04 };
59 byte[] xA005 =
60 { (byte)0xA0, (byte)0x05 };
61 byte[] xA006 =
62 { (byte)0xA0, (byte)0x06 };
63 byte[] xA007 =
64 { (byte)0xA0, (byte)0x07 };
65 byte[] xA008 =
66 { (byte)0xA0, (byte)0x08 };
67 byte[] xA009 =
68 { (byte)0xA0, (byte)0x09 };
69 byte[] xA00A =
70 { (byte)0xA0, (byte)0x0A };
71 byte[] xA00B =
72 { (byte)0xA0, (byte)0x0B };
73 __headerHash.put("Content-Type",xA001);
74 __headerHash.put("Content-Language",xA002);
75 __headerHash.put("Content-Length",xA003);
76 __headerHash.put("Date",xA004);
77 __headerHash.put("Last-Modified",xA005);
78 __headerHash.put("Location",xA006);
79 __headerHash.put("Set-Cookie",xA007);
80 __headerHash.put("Set-Cookie2",xA008);
81 __headerHash.put("Servlet-Engine",xA009);
82 __headerHash.put("Status",xA00A);
83 __headerHash.put("WWW-Authenticate",xA00B);
84
85 }
86
87
88
89
90 private static final byte[] AJP13_CPONG_RESPONSE =
91 { 'A', 'B', 0, 1, 9 };
92
93 private static final byte[] AJP13_END_RESPONSE =
94 { 'A', 'B', 0, 2, 5, 1 };
95
96
97
98
99
100 private static final byte[] AJP13_MORE_CONTENT =
101 { 'A', 'B', 0, 3, 6, 31, -7 };
102
103 private static String SERVER = "Server: Jetty(7.x.x)";
104
105 public static void setServerVersion(String version)
106 {
107 SERVER = "Jetty(" + version + ")";
108 }
109
110
111 private boolean _expectMore = false;
112
113 private boolean _needMore = false;
114
115 private boolean _needEOC = false;
116
117 private boolean _bufferPrepared = false;
118
119
120 public Ajp13Generator(Buffers buffers, EndPoint io)
121 {
122 super(buffers,io);
123 }
124
125
126 @Override
127 public boolean isRequest()
128 {
129 return false;
130 }
131
132
133 @Override
134 public boolean isResponse()
135 {
136 return true;
137 }
138
139
140 @Override
141 public void reset()
142 {
143 super.reset();
144
145 _needEOC = false;
146 _needMore = false;
147 _expectMore = false;
148 _bufferPrepared = false;
149 _last = false;
150
151 _state = STATE_HEADER;
152
153 _status = 0;
154 _version = HttpVersions.HTTP_1_1_ORDINAL;
155 _reason = null;
156 _method = null;
157 _uri = null;
158
159 _contentWritten = 0;
160 _contentLength = HttpTokens.UNKNOWN_CONTENT;
161 _last = false;
162 _head = false;
163 _noContent = false;
164 _persistent = true;
165
166 _header = null;
167 _buffer = null;
168 _content = null;
169
170 }
171
172
173 @Override
174 public int getContentBufferSize()
175 {
176 try
177 {
178 initContent();
179 }
180 catch (IOException e)
181 {
182 throw new RuntimeException(e);
183 }
184 return super.getContentBufferSize() - 7;
185 }
186
187
188 @Override
189 public void increaseContentBufferSize(int contentBufferSize)
190 {
191
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 public void addContent(Buffer content, boolean last) throws IOException
208 {
209 if (_noContent)
210 {
211 content.clear();
212 return;
213 }
214
215 if (content.isImmutable())
216 throw new IllegalArgumentException("immutable");
217
218 if (_last || _state == STATE_END)
219 {
220 LOG.debug("Ignoring extra content {}",content);
221 content.clear();
222 return;
223 }
224 _last = last;
225
226 if (!_endp.isOpen())
227 {
228 _state = STATE_END;
229 return;
230 }
231
232
233 if (_content != null && _content.length() > 0)
234 {
235
236 flushBuffer();
237 if (_content != null && _content.length() > 0)
238 throw new IllegalStateException("FULL");
239 }
240
241 _content = content;
242
243 _contentWritten += content.length();
244
245
246 if (_head)
247 {
248 content.clear();
249 _content = null;
250 }
251 else
252 {
253
254 initContent();
255
256 int len = 0;
257 len = _buffer.put(_content);
258
259
260 if (len > 0 && _buffer.space() == 0)
261 {
262 len--;
263 _buffer.setPutIndex(_buffer.putIndex() - 1);
264 }
265
266 _content.skip(len);
267
268 if (_content.length() == 0)
269 _content = null;
270 }
271 }
272
273
274
275
276
277
278
279
280 @Override
281 public int prepareUncheckedAddContent() throws IOException
282 {
283 if (_noContent)
284 return -1;
285
286 if (_last || _state == STATE_END)
287 throw new IllegalStateException("Closed");
288
289 if (!_endp.isOpen())
290 {
291 _state = STATE_END;
292 return -1;
293 }
294
295
296 Buffer content = _content;
297 if (content != null && content.length() > 0)
298 {
299 flushBuffer();
300 if (content != null && content.length() > 0)
301 throw new IllegalStateException("FULL");
302 }
303
304
305 initContent();
306
307 _contentWritten -= _buffer.length();
308
309
310 if (_head)
311 return Integer.MAX_VALUE;
312
313 return _buffer.space() - 1;
314 }
315
316
317 @Override
318 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
319 {
320 if (_state != STATE_HEADER)
321 return;
322
323 if (_last && !allContentAdded)
324 throw new IllegalStateException("last?");
325 _last = _last | allContentAdded;
326
327 boolean has_server = false;
328 if (_persistent == null)
329 _persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
330
331
332 if (_header == null)
333 _header = _buffers.getHeader();
334
335 Buffer tmpbuf = _buffer;
336 _buffer = _header;
337
338 try
339 {
340
341 _buffer.put((byte)'A');
342 _buffer.put((byte)'B');
343 addInt(0);
344 _buffer.put((byte)0x4);
345 addInt(_status);
346 if (_reason == null)
347 _reason = HttpGenerator.getReasonBuffer(_status);
348 if (_reason == null)
349 _reason = new ByteArrayBuffer(Integer.toString(_status));
350 addBuffer(_reason);
351
352 if (_status == 100 || _status == 204 || _status == 304)
353 {
354 _noContent = true;
355 _content = null;
356 }
357
358
359 int field_index = _buffer.putIndex();
360 addInt(0);
361
362 int num_fields = 0;
363
364 if (fields != null)
365 {
366
367 int s = fields.size();
368 for (int f = 0; f < s; f++)
369 {
370 HttpFields.Field field = fields.getField(f);
371 if (field == null)
372 continue;
373 num_fields++;
374
375 byte[] codes = (byte[])__headerHash.get(field.getName());
376 if (codes != null)
377 {
378 _buffer.put(codes);
379 }
380 else
381 {
382 addString(field.getName());
383 }
384 addString(field.getValue());
385 }
386 }
387
388 if (!has_server && _status > 100 && getSendServerVersion())
389 {
390 num_fields++;
391 addString("Server");
392 addString(SERVER);
393 }
394
395
396
397
398 int tmp = _buffer.putIndex();
399 _buffer.setPutIndex(field_index);
400 addInt(num_fields);
401 _buffer.setPutIndex(tmp);
402
403
404
405
406 int payloadSize = _buffer.length() - 4;
407
408
409
410 addInt(2,payloadSize);
411 }
412 finally
413 {
414 _buffer = tmpbuf;
415 }
416
417 _state = STATE_CONTENT;
418
419 }
420
421
422
423
424
425
426
427 @Override
428 public void complete() throws IOException
429 {
430 if (_state == STATE_END)
431 return;
432
433 super.complete();
434
435 if (_state < STATE_FLUSHING)
436 {
437 _state = STATE_FLUSHING;
438 _needEOC = true;
439 }
440
441 flushBuffer();
442 }
443
444
445 @Override
446 public int flushBuffer() throws IOException
447 {
448 try
449 {
450 if (_state == STATE_HEADER && !_expectMore)
451 throw new IllegalStateException("State==HEADER");
452 prepareBuffers();
453
454 if (_endp == null)
455 {
456
457
458
459
460
461
462 if (!_expectMore && _needEOC && _buffer != null)
463 {
464 _buffer.put(AJP13_END_RESPONSE);
465 }
466 _needEOC = false;
467 return 0;
468 }
469
470
471
472 int total = 0;
473 long last_len = -1;
474 Flushing: while (true)
475 {
476 int len = -1;
477 int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
478
479 switch (to_flush)
480 {
481 case 7:
482 throw new IllegalStateException();
483
484
485 case 6:
486 len = _endp.flush(_header,_buffer,null);
487
488 break;
489 case 5:
490 throw new IllegalStateException();
491
492
493 case 4:
494 len = _endp.flush(_header);
495 break;
496 case 3:
497 throw new IllegalStateException();
498
499
500 case 2:
501 len = _endp.flush(_buffer);
502
503 break;
504 case 1:
505 throw new IllegalStateException();
506
507
508 case 0:
509 {
510
511 if (_header != null)
512 _header.clear();
513
514 _bufferPrepared = false;
515
516 if (_buffer != null)
517 {
518 _buffer.clear();
519
520
521
522 _buffer.setPutIndex(7);
523 _buffer.setGetIndex(7);
524
525
526
527
528
529 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
530 {
531
532 _buffer.put(_content);
533 _content.clear();
534 _content = null;
535 break Flushing;
536 }
537
538 }
539
540
541 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
542 {
543 if (_state == STATE_FLUSHING)
544 _state = STATE_END;
545
546
547
548
549
550
551
552 break Flushing;
553 }
554
555
556 prepareBuffers();
557 }
558 }
559
560
561
562 if (len <= 0)
563 {
564 if (last_len <= 0)
565 break Flushing;
566 break;
567 }
568 last_len = len;
569 total += len;
570 }
571
572 return total;
573 }
574 catch (IOException e)
575 {
576 LOG.ignore(e);
577 throw (e instanceof EofException)?e:new EofException(e);
578 }
579
580 }
581
582
583 private void prepareBuffers()
584 {
585 if (!_bufferPrepared)
586 {
587
588
589 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
590 {
591
592 int len = _buffer.put(_content);
593
594
595 if (len > 0 && _buffer.space() == 0)
596 {
597 len--;
598 _buffer.setPutIndex(_buffer.putIndex() - 1);
599 }
600 _content.skip(len);
601
602 if (_content.length() == 0)
603 _content = null;
604
605 if (_buffer.length() == 0)
606 {
607 _content = null;
608 }
609 }
610
611
612 if (_buffer != null)
613 {
614
615 int payloadSize = _buffer.length();
616
617
618
619
620
621
622 if (payloadSize > 0)
623 {
624 _bufferPrepared = true;
625
626 _buffer.put((byte)0);
627 int put = _buffer.putIndex();
628 _buffer.setGetIndex(0);
629 _buffer.setPutIndex(0);
630 _buffer.put((byte)'A');
631 _buffer.put((byte)'B');
632 addInt(payloadSize + 4);
633 _buffer.put((byte)3);
634 addInt(payloadSize);
635 _buffer.setPutIndex(put);
636 }
637 }
638
639 if (_needMore)
640 {
641
642 if (_header == null)
643 {
644 _header = _buffers.getHeader();
645 }
646
647 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
648 {
649 _header.put(AJP13_MORE_CONTENT);
650 _needMore = false;
651 }
652 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
653 {
654
655
656 _buffer.put(AJP13_MORE_CONTENT);
657 _needMore = false;
658 _bufferPrepared = true;
659 }
660
661 }
662
663 if (!_expectMore && _needEOC)
664 {
665 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
666 {
667
668 _header.put(AJP13_END_RESPONSE);
669 _needEOC = false;
670 }
671 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
672 {
673
674
675
676 _buffer.put(AJP13_END_RESPONSE);
677 _needEOC = false;
678 _bufferPrepared = true;
679 }
680 }
681 }
682 }
683
684
685 @Override
686 public boolean isComplete()
687 {
688 return !_expectMore && _state == STATE_END;
689 }
690
691
692 private void initContent() throws IOException
693 {
694 if (_buffer == null)
695 {
696 _buffer = _buffers.getBuffer();
697 _buffer.setPutIndex(7);
698 _buffer.setGetIndex(7);
699 }
700 }
701
702
703 private void addInt(int i)
704 {
705 _buffer.put((byte)((i >> 8) & 0xFF));
706 _buffer.put((byte)(i & 0xFF));
707 }
708
709
710 private void addInt(int startIndex, int i)
711 {
712 _buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
713 _buffer.poke((startIndex + 1),(byte)(i & 0xFF));
714 }
715
716
717 private void addString(String str) throws UnsupportedEncodingException
718 {
719 if (str == null)
720 {
721 addInt(0xFFFF);
722 return;
723 }
724
725
726
727 byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
728
729 addInt(b.length);
730
731 _buffer.put(b);
732 _buffer.put((byte)0);
733 }
734
735
736 private void addBuffer(Buffer b)
737 {
738 if (b == null)
739 {
740 addInt(0xFFFF);
741 return;
742 }
743
744 addInt(b.length());
745 _buffer.put(b);
746 _buffer.put((byte)0);
747 }
748
749
750 public void getBodyChunk() throws IOException
751 {
752 ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
753 _endp.flush(bf);
754 }
755
756
757 public void gotBody()
758 {
759 _needMore = false;
760 _expectMore = false;
761 }
762
763
764 public void sendCPong() throws IOException
765 {
766
767 Buffer buff = _buffers.getBuffer();
768 buff.put(AJP13_CPONG_RESPONSE);
769
770
771 do
772 {
773 _endp.flush(buff);
774 }
775 while (buff.length() > 0);
776 _buffers.returnBuffer(buff);
777
778 reset();
779
780 }
781
782 }