Update Iot.js
[platform/upstream/iotjs.git] / src / js / http_outgoing.js
1 /* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16
17 var util = require('util');
18 var stream = require('stream');
19
20
21 function OutgoingMessage() {
22   stream.Stream.call(this);
23
24   this.writable = true;
25
26   this._hasBody = true;
27
28   this.finished = false;
29   this._sentHeader = false;
30
31   this.socket = null;
32   this.connection = null;
33   // response header string : same 'content' as this._headers
34   this._header = null;
35   // response header obj : (key, value) pairs
36   this._headers = {};
37
38 }
39
40 util.inherits(OutgoingMessage, stream.Stream);
41
42 exports.OutgoingMessage = OutgoingMessage;
43
44
45 OutgoingMessage.prototype.end = function(data, encoding, callback) {
46   var self = this;
47
48   if (util.isFunction(data)) {
49     callback = data;
50     data = null;
51   } else if (util.isFunction(encoding)) {
52     callback = encoding;
53     encoding = null;
54   }
55
56   if (this.finished) {
57     return false;
58   }
59
60   // flush header
61   if (!this._header) {
62     this._implicitHeader();
63   }
64
65   if (data) {
66     this.write(data, encoding);
67   }
68
69   // Register finish event handler.
70   if (util.isFunction(callback)) {
71     this.once('finish', callback);
72   }
73
74   // Force flush buffered data.
75   // After all data was sent, emit 'finish' event meaning segment of header and
76   // body were all sent finished. This means different from 'finish' event
77   // emitted by net which indicate there will be no more data to be sent through
78   // the connection. On the other hand emitting 'finish' event from http does
79   // not neccessarily imply end of data transmission since there might be
80   // another segment of data when connection is 'Keep-Alive'.
81   this._send('', function() {
82     self.emit('finish');
83   });
84
85
86   this.finished = true;
87
88   this._finish();
89
90   return true;
91 };
92
93
94 OutgoingMessage.prototype._finish = function() {
95   this.emit('prefinish');
96 };
97
98
99 // This sends chunk directly into socket
100 // TODO: buffering of chunk in the case of socket is not available
101 OutgoingMessage.prototype._send = function(chunk, encoding, callback) {
102   if (util.isFunction(encoding)) {
103     callback = encoding;
104   }
105
106   if (util.isBuffer(chunk)) {
107     chunk = chunk.toString();
108   }
109
110   if (!this._sentHeader) {
111     chunk = this._header + "\r\n" + chunk;
112     this._sentHeader = true;
113   }
114
115   return this.connection.write(chunk, encoding, callback);
116 };
117
118
119 OutgoingMessage.prototype.write = function(chunk, encoding, callback) {
120   if (!this._header) {
121     this._implicitHeader();
122   }
123
124   if (!this._hasBody) {
125     return true;
126   }
127
128   var ret = this._send(chunk, encoding, callback);
129
130   return ret;
131
132 };
133
134
135 // Stringfy header fields of _headers into _header
136 OutgoingMessage.prototype._storeHeader = function(statusLine) {
137   var headerStr = '';
138
139   var keys;
140   if (this._headers) {
141     keys = Object.keys(this._headers);
142     for (var i=0; i<keys.length; i++) {
143       var key = keys[i];
144       headerStr += key + ": " + this._headers[key] + '\r\n';
145     }
146   }
147
148   this._header = statusLine + headerStr;
149
150 };
151
152
153 OutgoingMessage.prototype.setHeader = function(name, value) {
154
155   if (this._headers === null) {
156     this._headers = {};
157   }
158
159   this._headers[name] = value;
160
161 };
162
163
164 OutgoingMessage.prototype.removeHeader = function(name) {
165   if (this._headers === null) {
166     return;
167   }
168
169   delete this._headers[name];
170 };
171
172
173 OutgoingMessage.prototype.getHeader = function(name) {
174   return this._headers[name];
175 };
176
177
178 OutgoingMessage.prototype.setTimeout = function(ms, cb) {
179   if (cb)
180     this.once('timeout', cb);
181
182   if (!this.socket) {
183     this.once('socket', function(socket) {
184       socket.setTimeout(msecs);
185     });
186   } else
187     this.socket.setTimeout(msecs);
188 };