├── .gitignore
├── LICENSE
├── Readme.md
├── build
├── bin
│ ├── .keep
│ └── dunit.ini
└── dcu
│ └── .keep
├── examples
└── customerrors
│ ├── build
│ ├── bin
│ │ └── .keep
│ └── dcu
│ │ └── .keep
│ ├── dunit.ini
│ ├── testcustomerrors.dof
│ ├── testcustomerrors.dpr
│ ├── testcustomerrors.res
│ ├── ujsonrpccustomerrors.pas
│ └── utestcustomerrors.pas
├── json-rpc-projects.bpg
├── projects
├── testjsonrpclite.dof
└── testjsonrpclite.dpr
├── source
├── ujsonrpc2.pas
└── utils
│ ├── FastMM4.pas
│ ├── FastMM4Messages.pas
│ ├── FastMM4Messages_ru.pas
│ └── FastMM4Options.inc
└── test
├── testjsonrpc.pas
└── testjsonrpcerrors.pas
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 | /projects/testjsonrpclite.res
68 | *.ppu
69 | *.bak
70 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Pascal JSON-RPC lite 2
2 |
3 | Parse and Serialize JSON-RPC2 messages in free-pascal or Delphi application.
4 | Git Repository: https://github.com/r3code/pascal-jsonrpc-lite-2
5 |
6 | This is an enhanced version of https://github.com/r3code/pascal-jsonrpc-lite
7 |
8 | Inspired by https://github.com/teambition/jsonrpc-lite.
9 |
10 | **An implementation of [JSON-RPC 2.0 specifications](http://jsonrpc.org/specification)**
11 |
12 |
13 | ## Dependencies
14 |
15 | SuperObject JSON parsing library https://github.com/hgourvest/superobject
16 |
17 |
18 | ## Install
19 |
20 | 1. Download.
21 | 2. Extract.
22 | 3. Add `ujsonrpc2.pas` to your project or add path to `ujsonrpc2.pas` to Lib Path.
23 | ```pascal
24 | uses ujsonrpc2;
25 | ```
26 |
27 |
28 | ## API
29 |
30 | ### Interface: IJsonRpcMessage
31 |
32 |
33 | #### Method: IJsonRpcMessage.AsJsonObject
34 |
35 | Returns object as ISuperObject.
36 |
37 | #### Method: IJsonRpcMessage.AsJSon(indent: boolean = false; escape: boolean = true): string;
38 |
39 | Returns a JSON string object representation.
40 |
41 | Params:
42 | - `indent`: {boolean} indent resulting JSON
43 | - `escape`: {boolean} escape special chars
44 |
45 |
46 | ### Class: TJsonRpcMessage
47 |
48 | ##### Class Method: TJsonRpcMessage.Request(id, method, params)
49 |
50 | Creates a JSON-RPC 2.0 request object, return IJsonRpcMessage object.
51 | Realizes IJsonRpcMessage. Returns {IJsonRpcError}.
52 |
53 | Params:
54 | - `id`: {String}
55 | - `method`: {String}
56 | - `params`: {ISuperObject}
57 |
58 | Example:
59 | ```pascal
60 | var requestObj: TJsonRpcMessage;
61 | requestObj := TJsonRpcMessage.Request('123', 'update', SO('{list: [1, 2, 3]}'));
62 | writeln(requestObj.asString);
63 | // {
64 | // jsonrpc: '2.0',
65 | // id: '123',
66 | // method: 'update',
67 | // params: {list: [1, 2, 3]}
68 | // }
69 | ```
70 |
71 | ##### Class Method: TJsonRpcMessage.Notification(method, params)
72 |
73 | Creates a JSON-RPC 2.0 notification object, returns {IJsonRpcMessage}.
74 |
75 | Params:
76 | - `method`: {String}
77 | - `params`: {ISuperObject}
78 |
79 | Example:
80 | ```pascal
81 | var notificationObj: TJsonRpcMessage;
82 | notificationObj := TJsonRpcMessage.notification('update', SO('{list: [1, 2, 3]}'));
83 | writeln(notificationObj.asString);
84 | // {
85 | // jsonrpc: '2.0',
86 | // method: 'update',
87 | // params: {list: [1, 2, 3]}
88 | // }
89 | ```
90 |
91 | #### Class Method: TJsonRpcMessage.Success(id, result)
92 |
93 | Creates a JSON-RPC 2.0 success response object, returns {IJsonRpcMessage}.
94 |
95 | Params:
96 | - `id`: {String}
97 | - `result`: {ISuperObject}
98 |
99 | Example:
100 | ```pascal
101 | var msg: TJsonRpcMessage;
102 | msg := TJsonRpcMessage.success('123', 'OK');
103 | writeln(msg.asString);
104 | // {
105 | // jsonrpc: '2.0',
106 | // id: '123',
107 | // result: 'OK',
108 | // }
109 | ```
110 |
111 | #### Class Method: TJsonRpcMessage.Error(id, error)
112 |
113 | Creates a JSON-RPC 2.0 error response object, returns {IJsonRpcMessage}.
114 |
115 | Params:
116 | - `id`: {String}
117 | - `error`: {IJsonRpcError} use TJsonRpcError or it's siblings
118 |
119 | Example:
120 | ```pascal
121 | var msg: TJsonRpcMessage;
122 | msg := TJsonRpcMessage.Error('123', TJsonRpcError.Create(-32000, 'some error', 'blabla'));
123 | writeln(msg.asString);
124 | // {
125 | // jsonrpc: '2.0',
126 | // id: '123',
127 | // error: {code: -32000, 'message': 'some error', data: 'blabla'},
128 | // }
129 | ```
130 |
131 | #### Class Method: TJsonRpcMessage.Parse(s, err)
132 |
133 | Takes a JSON-RPC 2.0 payload (string) and tries to parse it into a JSON.
134 | If successful, determine what object is it (response, notification, success,
135 | error, or invalid), and return it's type and properly formatted object.
136 | In case of error see details in `err` value.
137 |
138 | Params:
139 | - `s`: {String}
140 | - `err`: {IJsonRpcError}
141 |
142 | Returns one of {IJsonRpcParsedMessage} realizations if OK,
143 | else `nil` and `err` set to one of {IJsonRpcError} realizations (e.g. TJsonRpcError).
144 |
145 |
146 | ### Enum: TJsonRpcObjectType
147 |
148 | Shows the type of message detected during `Parse`.
149 | Types: `jotInvalid`, `jotRequest`, `jotNotification`, `jotSuccess`, `jotError`.
150 |
151 |
152 | ### Interface: IJsonRpcParsedMessage
153 |
154 | #### Method: IJsonRpcParsedMessage.GetMessageType
155 |
156 | Returns one of {TJsonRpcObjectType}.
157 |
158 | #### Method: IJsonRpcParsedMessage.GetMessagePayload
159 |
160 | Returns stored ref to {IJsonRpcMessage}.
161 |
162 |
163 | ### Class: TJsonRpcParsedMessage
164 |
165 | Realizes interface {IJsonRpcParsedMessage}.
166 |
167 | #### Constructor: TJsonRpcParsedMessage.Create(objType, payload)
168 |
169 | Create an instance.
170 |
171 | Params:
172 | - `objType`: {TJsonRpcObjectType} message format type
173 | - `payload`: {IJsonRpcMessage} message body
174 |
175 |
176 | ### Interface: IJsonRpcError
177 |
178 | #### Method: IJsonRpcError.GetCode
179 |
180 | Returns error code as {Integer}.
181 |
182 | #### Method: IJsonRpcError.GetMessage
183 |
184 | Returns error message as {String}.
185 |
186 | #### Method: IJsonRpcError.GetData
187 |
188 | Returns error Data as {ISuperObject}.
189 |
190 | #### Method: IJsonRpcError.AsJsonObject
191 |
192 | Returns object as {ISuperObject}.
193 |
194 |
195 | ### Class: TJsonRpcError
196 |
197 | Describes JSON-RPC 2.0 Error object.
198 | Realizes interface {IJsonRpcMessage}.
199 |
200 | #### Constructor: TJsonRpcError.Create(code,message[,data])
201 |
202 | Creates an instance.
203 |
204 | Params:
205 | - `code`: {Integer}
206 | - `message`: {String}
207 | - `data`: {ISuperObject} optional
208 |
209 | Examples:
210 | ```pascal
211 | var error: TJsonRpcError;
212 | error = TJsonRpcError.Create(-32651, 'some error', 'some data');
213 | ```
214 | or
215 | ```pascal
216 | var error: TJsonRpcError;
217 | error = TJsonRpcError.Create(-32651, 'some error', SO('{ a: 1, extra: "some data"}'));
218 | ```
219 |
220 | #### Class Method: TJsonRpcError.InvalidRequest(data)
221 |
222 | Create {TJsonRpcError} object with error code -32600.
223 |
224 | Params:
225 | - `data`: {ISuperObject|nil} - extra data
226 |
227 | #### Class Method: TJsonRpcError.MethodNotFound(data)
228 |
229 | Create {TJsonRpcError} object with error code -32601.
230 |
231 | Params:
232 | - `data`: {ISuperObject|nil} - extra data
233 |
234 | #### Class Method: TJsonRpcError.InvalidParams(data)
235 |
236 | Create {TJsonRpcError} object with error code -32602.
237 |
238 | Params:
239 | - `data`: {ISuperObject|nil} - extra data
240 |
241 | #### Class Method: TJsonRpcError.InternalError(data)
242 |
243 | Create {TJsonRpcError} object with error code -32603.
244 |
245 | Params:
246 | - `data`: {ISuperObject|nil} - extra data
247 |
248 | #### Class Method: TJsonRpcError.ParseError(data)
249 |
250 | Create {TJsonRpcError} object with error code -32700.
251 |
252 | Params:
253 | - `data`: {String} - error text
254 |
255 |
256 | ### Class: TJsonRpcNotificationObject
257 |
258 | Describes JSON-RPC 2.0 Notification object.
259 | Realizes interface {IJsonRpcMessage}.
260 |
261 | #### Constructor: TJsonRpcNotificationObject.Create(method[,params])
262 |
263 | Creates an instance.
264 |
265 | Params:
266 | - `method`: {String}
267 | - `params`: {TSuperArray|ISuperObject} optional
268 |
269 | For TSuperArray use SA() or SO([array, items]).
270 |
271 |
272 | #### Class Method: TJsonRpcNotificationObject.AsJsonObject
273 |
274 | Returns object as {ISuperObject}
275 |
276 |
277 | ### Class: TJsonRpcRequestObject
278 |
279 | Describes JSON-RPC 2.0 Request object.
280 | Realizes interface {IJsonRpcMessage}.
281 |
282 | #### Constructor: TJsonRpcRequestObject.Create(id, method[,params])
283 |
284 | Creates an instance.
285 |
286 | Params:
287 | - `id`: {String}
288 | - `method`: {String}
289 | - `params`: {TSuperArray|ISuperObject} optional
290 |
291 | For TSuperArray use SA() or SO([array, items]).
292 |
293 |
294 | #### Class Method: TJsonRpcRequestObject.AsJsonObject
295 |
296 | Returns object as {ISuperObject}
297 |
298 |
299 | ### Class: TJsonRpcSuccessObject
300 |
301 | Describes JSON-RPC 2.0 Success object.
302 | Realizes interface {IJsonRpcMessage}.
303 |
304 | #### Constructor: TJsonRpcSuccessObject.Create(id, result)
305 |
306 | Create a {TJsonRpcSuccessObject} instance.
307 |
308 | Params:
309 | - `id`: {String}
310 | - `result`: {ISuperObject}
311 |
312 | To place scalar value as result use superobject as wrapper: `SO('string value'); SO(921)`
313 |
314 |
315 | #### Class Method: TJsonRpcSuccessObject.AsJsonObject
316 |
317 | Returns object as {ISuperObject}
318 |
319 |
320 | ### Class: TJsonRpcErrorObject
321 |
322 | Describes JSON-RPC 2.0 Error object.
323 | Realizes interface {IJsonRpcMessage}.
324 |
325 | #### Constructor: TJsonRpcErrorObject.Create(id, method[,params])
326 |
327 | Creates an instance.
328 |
329 | Params:
330 | - `id`: {String}
331 | - `result`: {ISuperObject}
332 |
333 | To place scalar value as result use superobject as wrapper: `SO('string value'); SO(921)`
334 |
335 |
336 | #### Class Method: TJsonRpcErrorObject.AsJsonObject
337 |
338 | Returns object as {ISuperObject}
--------------------------------------------------------------------------------
/build/bin/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/build/bin/.keep
--------------------------------------------------------------------------------
/build/bin/dunit.ini:
--------------------------------------------------------------------------------
1 | [GUITestRunner Config]
2 | AutoSave=1
3 | Left=358
4 | Top=1
5 | Width=1012
6 | Height=1010
7 | Maximized=0
8 | UseRegistry=0
9 | ResultsPanel.Height=175
10 | ErrorMessage.Height=294
11 | ErrorMessage.Visible=1
12 | FailureList.ColumnWidth[0]=120
13 | FailureList.ColumnWidth[1]=100
14 | FailureList.ColumnWidth[2]=200
15 | FailureList.ColumnWidth[3]=564
16 | HideTestNodesOnOpen=0
17 | BreakOnFailures=0
18 | FailOnNoChecksExecuted=0
19 | FailOnMemoryLeaked=0
20 | IgnoreSetUpTearDownLeaks=0
21 | ReportMemoryLeakTypes=1
22 | SelectTestedNode=1
23 | WarnOnFailTestOverride=0
24 | PopupX=350
25 | PopupY=30
26 |
27 | [Tests.testjsonrpclite.exe.TTestJsonRpc]
28 |
29 | [Tests.testjsonrpclite.exe]
30 |
31 | [Tests.testjsonrpclite.exe.TTestJsonRpcError]
32 |
33 |
--------------------------------------------------------------------------------
/build/dcu/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/build/dcu/.keep
--------------------------------------------------------------------------------
/examples/customerrors/build/bin/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/examples/customerrors/build/bin/.keep
--------------------------------------------------------------------------------
/examples/customerrors/build/dcu/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/examples/customerrors/build/dcu/.keep
--------------------------------------------------------------------------------
/examples/customerrors/dunit.ini:
--------------------------------------------------------------------------------
1 | [GUITestRunner Config]
2 | AutoSave=1
3 | Left=175
4 | Top=175
5 | Width=500
6 | Height=500
7 | Maximized=1
8 | UseRegistry=0
9 | ResultsPanel.Height=174
10 | ErrorMessage.Height=75
11 | ErrorMessage.Visible=1
12 | FailureList.ColumnWidth[0]=120
13 | FailureList.ColumnWidth[1]=100
14 | FailureList.ColumnWidth[2]=200
15 | FailureList.ColumnWidth[3]=1248
16 | HideTestNodesOnOpen=0
17 | BreakOnFailures=0
18 | FailOnNoChecksExecuted=1
19 | FailOnMemoryLeaked=1
20 | IgnoreSetUpTearDownLeaks=0
21 | ReportMemoryLeakTypes=0
22 | SelectTestedNode=1
23 | WarnOnFailTestOverride=0
24 | PopupX=350
25 | PopupY=30
26 |
27 |
--------------------------------------------------------------------------------
/examples/customerrors/testcustomerrors.dof:
--------------------------------------------------------------------------------
1 | [FileVersion]
2 | Version=7.0
3 | [Compiler]
4 | A=8
5 | B=0
6 | C=1
7 | D=1
8 | E=0
9 | F=0
10 | G=1
11 | H=1
12 | I=1
13 | J=0
14 | K=0
15 | L=1
16 | M=0
17 | N=1
18 | O=0
19 | P=1
20 | Q=1
21 | R=1
22 | S=0
23 | T=0
24 | U=0
25 | V=1
26 | W=1
27 | X=1
28 | Y=1
29 | Z=1
30 | ShowHints=1
31 | ShowWarnings=1
32 | UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
33 | NamespacePrefix=
34 | SymbolDeprecated=1
35 | SymbolLibrary=1
36 | SymbolPlatform=1
37 | UnitLibrary=1
38 | UnitPlatform=1
39 | UnitDeprecated=1
40 | HResultCompat=1
41 | HidingMember=1
42 | HiddenVirtual=1
43 | Garbage=1
44 | BoundsError=1
45 | ZeroNilCompat=1
46 | StringConstTruncated=1
47 | ForLoopVarVarPar=1
48 | TypedConstVarPar=1
49 | AsgToTypedConst=1
50 | CaseLabelRange=1
51 | ForVariable=1
52 | ConstructingAbstract=1
53 | ComparisonFalse=1
54 | ComparisonTrue=1
55 | ComparingSignedUnsigned=1
56 | CombiningSignedUnsigned=1
57 | UnsupportedConstruct=1
58 | FileOpen=1
59 | FileOpenUnitSrc=1
60 | BadGlobalSymbol=1
61 | DuplicateConstructorDestructor=1
62 | InvalidDirective=1
63 | PackageNoLink=1
64 | PackageThreadVar=1
65 | ImplicitImport=1
66 | HPPEMITIgnored=1
67 | NoRetVal=1
68 | UseBeforeDef=1
69 | ForLoopVarUndef=1
70 | UnitNameMismatch=1
71 | NoCFGFileFound=1
72 | MessageDirective=1
73 | ImplicitVariants=1
74 | UnicodeToLocale=1
75 | LocaleToUnicode=1
76 | ImagebaseMultiple=1
77 | SuspiciousTypecast=1
78 | PrivatePropAccessor=1
79 | UnsafeType=1
80 | UnsafeCode=1
81 | UnsafeCast=1
82 | [Linker]
83 | MapFile=3
84 | OutputObjs=0
85 | ConsoleApp=1
86 | DebugInfo=0
87 | RemoteSymbols=0
88 | MinStackSize=16384
89 | MaxStackSize=1048576
90 | ImageBase=4194304
91 | ExeDescription=
92 | [Directories]
93 | OutputDir=
94 | UnitOutputDir=
95 | PackageDLLOutputDir=
96 | PackageDCPOutputDir=
97 | SearchPath=..\..\source
98 | Packages=vcl;rtl;dbrtl;inet;inetdb;dsnap;bdertl;vclx;vcldb;vcldbx;visualclx;visualdbclx;vclactnband;vclshlctrls;vclie;xmlrtl;inetdbbde;inetdbxpress;webdsnap;soaprtl;websnap;adortl;dbexpress;dsnapcon;dbxcds;ibxpress;teeui;teedb;tee;dclOfficeXP;VclNewlyext;JclDeveloperTools;Jcl;JclVcl;JclContainers;madBasic_;madDisAsm_;madExcept_;ZComponent;ZParseSql;ZCore;ZDbc;ZPlain
99 | Conditionals=DEBUG;FastMM
100 | DebugSourceDirs=
101 | UsePackages=0
102 | [Parameters]
103 | RunParams=
104 | HostApplication=
105 | Launcher=
106 | UseLauncher=0
107 | DebugCWD=
108 | [Language]
109 | ActiveLang=
110 | ProjectLang=
111 | RootDir=C:\Program Files\Borland\Delphi7\Bin\
112 | [Version Info]
113 | IncludeVerInfo=0
114 | AutoIncBuild=0
115 | MajorVer=1
116 | MinorVer=0
117 | Release=0
118 | Build=0
119 | Debug=0
120 | PreRelease=0
121 | Special=0
122 | Private=0
123 | DLL=0
124 | Locale=1049
125 | CodePage=1251
126 | [Version Info Keys]
127 | FileVersion=1.0.0.0
128 | [Excluded Packages]
129 | c:\program files\borland\delphi7\Bin\dclindy70.bpl=Internet Direct (Indy) for D7 Property and Component Editors
130 | [HistoryLists\hlConditionals]
131 | Count=3
132 | Item0=Debug;FastMM
133 | Item1=FastMM
134 | Item2=DEBUG
135 | [HistoryLists\hlUnitAliases]
136 | Count=1
137 | Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
138 | [HistoryLists\hlSearchPath]
139 | Count=4
140 | Item0=..\..\source
141 | Item1=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug;.\;..\Source;..\Source\utils
142 | Item2=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug;.\;..\Source
143 | Item3=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug
144 | [HistoryLists\hlUnitOutputDirectory]
145 | Count=1
146 | Item0=..\build\dcu
147 | [HistoryLists\hlOutputDirectorry]
148 | Count=1
149 | Item0=..\build\bin
150 | [HistoryLists\hlBPLOutput]
151 | Count=1
152 | Item0=..\build\bin
153 |
--------------------------------------------------------------------------------
/examples/customerrors/testcustomerrors.dpr:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Dmitriy S. Sinyavskiy, 2016
3 | //
4 |
5 | //{$DEFINE DUNIT_CONSOLE_MODE}
6 |
7 | program testcustomerrors;
8 |
9 | {%File '..\..\source\utils\FastMM4Options.inc'}
10 |
11 | uses
12 | FastMM4,
13 | SysUtils,
14 | TestFramework,
15 | TestExtensions,
16 | GUITestRunner,
17 | TextTestRunner,
18 | ujsonrpccustomerrors in 'ujsonrpccustomerrors.pas',
19 | utestcustomerrors in 'utestcustomerrors.pas',
20 | ujsonrpc2 in '..\..\source\ujsonrpc2.pas';
21 |
22 | {$IFDEF DUNIT_CONSOLE_MODE}
23 | {$APPTYPE CONSOLE}
24 | {$ELSE}
25 | {$R *.RES}
26 | {$ENDIF}
27 |
28 | begin
29 | {$IFDEF DUNIT_CONSOLE_MODE}
30 | if not FindCmdLineSwitch('Graphic', ['-', '/'], True) then
31 | TextTestRunner.RunRegisteredTests(rxbHaltOnFailures)
32 | else
33 | {$ENDIF}
34 | GUITestRunner.RunRegisteredTests;
35 | end.
36 |
--------------------------------------------------------------------------------
/examples/customerrors/testcustomerrors.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/examples/customerrors/testcustomerrors.res
--------------------------------------------------------------------------------
/examples/customerrors/ujsonrpccustomerrors.pas:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Dmitriy S. Sinyavskiy, 2016
3 | //
4 | unit ujsonrpccustomerrors;
5 |
6 | {$IFDEF FPC}
7 | {$MODE objfpc}
8 | {$ENDIF}
9 |
10 | interface
11 |
12 | uses
13 | Classes, SysUtils, superobject, ujsonrpc2;
14 |
15 | type
16 |
17 | { TJsonRpcCustomError }
18 |
19 | TJsonRpcCustomError = class
20 | class function ProcedureException(data: ISuperObject): IJsonRpcError;
21 | overload;
22 | class function ProcedureException(data: string): IJsonRpcError; overload;
23 | class function AuthError(data: ISuperObject): IJsonRpcError; overload;
24 | class function AuthError(data: string): IJsonRpcError; overload;
25 | end;
26 |
27 | implementation
28 |
29 | const
30 | errorProcedureException = 'Procedure Exception';
31 | codeProcedureException = -32200;
32 | errorAuthError = 'Authentication Error';
33 | codeAuthError = -32201;
34 |
35 | { TJsonRpcCustomError }
36 |
37 | class function TJsonRpcCustomError.ProcedureException(data: ISuperObject
38 | ): IJsonRpcError;
39 | begin
40 | result := TJsonRpcError.Error(codeProcedureException, errorProcedureException,
41 | data);
42 | end;
43 |
44 | class function TJsonRpcCustomError.ProcedureException(
45 | data: string): IJsonRpcError;
46 | begin
47 | result := TJsonRpcError.Error(codeProcedureException, errorProcedureException,
48 | data);
49 | end;
50 |
51 | class function TJsonRpcCustomError.AuthError(data: ISuperObject): IJsonRpcError;
52 | begin
53 | result := TJsonRpcError.Error(codeAuthError, errorAuthError, data);
54 | end;
55 |
56 | class function TJsonRpcCustomError.AuthError(data: string): IJsonRpcError;
57 | begin
58 | result := TJsonRpcError.Error(codeAuthError, errorAuthError, data);
59 | end;
60 |
61 | end.
62 |
--------------------------------------------------------------------------------
/examples/customerrors/utestcustomerrors.pas:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Dmitriy S. Sinyavskiy, 2016
3 | //
4 | unit utestcustomerrors;
5 |
6 | interface
7 |
8 | uses
9 | Windows, SysUtils, Classes, TestFramework, TestExtensions;
10 |
11 | type
12 | TTestCustomErrors = class(TTestCase)
13 | published
14 | procedure TestProcedureExceptionWithDataStr;
15 | procedure TestProcedureExceptionWithDataObj;
16 | procedure TestAuthErrorWithDataStr;
17 | procedure TestAuthErrorWithDataObj;
18 | end;
19 |
20 | implementation
21 |
22 | uses
23 | ujsonrpccustomerrors, ujsonrpc2, superobject;
24 |
25 | procedure TTestCustomErrors.TestAuthErrorWithDataObj;
26 | var
27 | expected, actual: iJsonRpcError;
28 | begin
29 | expected := TJsonRpcError.Create(-32201, 'Authentication Error',
30 | SO('blabla'));
31 | actual := TJsonRpcCustomError.AuthError(SO('blabla'));
32 | CheckEquals(expected.AsJsonObject.AsJSon(), actual.AsJsonObject.AsJSon());
33 | end;
34 |
35 | procedure TTestCustomErrors.TestAuthErrorWithDataStr;
36 | var
37 | expected, actual: IJsonRpcError;
38 | begin
39 | expected := TJsonRpcError.Create(-32201, 'Authentication Error', 'blabla');
40 | actual := TJsonRpcCustomError.AuthError('blabla');
41 | CheckEquals(expected.AsJsonObject.AsJSon(), actual.AsJsonObject.AsJSon());
42 | end;
43 |
44 | procedure TTestCustomErrors.TestProcedureExceptionWithDataObj;
45 | var
46 | expected, actual: IJsonRpcError;
47 | begin
48 | expected := TJsonRpcError.Create(-32200, 'Procedure Exception', SO('blabla'));
49 | actual := TJsonRpcCustomError.ProcedureException(SO('blabla'));
50 | CheckEquals(expected.AsJsonObject.AsJSon(), actual.AsJsonObject.AsJSon());
51 | end;
52 |
53 | procedure TTestCustomErrors.TestProcedureExceptionWithDataStr;
54 | var
55 | expected, actual: IJsonRpcError;
56 | begin
57 | expected := TJsonRpcError.Create(-32200, 'Procedure Exception', 'blabla');
58 | actual := TJsonRpcCustomError.ProcedureException('blabla');
59 | CheckEquals(expected.AsJsonObject.AsJSon(), actual.AsJsonObject.AsJSon());
60 | end;
61 |
62 | initialization
63 | TestFramework.RegisterTest(TTestCustomErrors.Suite);
64 |
65 | end.
66 |
--------------------------------------------------------------------------------
/json-rpc-projects.bpg:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------------
2 | VERSION = BWS.01
3 | #------------------------------------------------------------------------------
4 | !ifndef ROOT
5 | ROOT = $(MAKEDIR)\..
6 | !endif
7 | #------------------------------------------------------------------------------
8 | MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$**
9 | DCC = $(ROOT)\bin\dcc32.exe $**
10 | BRCC = $(ROOT)\bin\brcc32.exe $**
11 | #------------------------------------------------------------------------------
12 | PROJECTS = testjsonrpclite.exe testcustomerrors.exe
13 | #------------------------------------------------------------------------------
14 | default: $(PROJECTS)
15 | #------------------------------------------------------------------------------
16 |
17 | testjsonrpclite.exe: projects\testjsonrpclite.dpr
18 | $(DCC)
19 |
20 | testcustomerrors.exe: examples\customerrors\testcustomerrors.dpr
21 | $(DCC)
22 |
23 |
24 |
--------------------------------------------------------------------------------
/projects/testjsonrpclite.dof:
--------------------------------------------------------------------------------
1 | [FileVersion]
2 | Version=7.0
3 | [Compiler]
4 | A=8
5 | B=0
6 | C=1
7 | D=1
8 | E=0
9 | F=0
10 | G=1
11 | H=1
12 | I=1
13 | J=0
14 | K=0
15 | L=1
16 | M=0
17 | N=1
18 | O=0
19 | P=1
20 | Q=1
21 | R=1
22 | S=0
23 | T=0
24 | U=0
25 | V=1
26 | W=1
27 | X=1
28 | Y=1
29 | Z=1
30 | ShowHints=1
31 | ShowWarnings=1
32 | UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
33 | NamespacePrefix=
34 | SymbolDeprecated=1
35 | SymbolLibrary=1
36 | SymbolPlatform=1
37 | UnitLibrary=1
38 | UnitPlatform=1
39 | UnitDeprecated=1
40 | HResultCompat=1
41 | HidingMember=1
42 | HiddenVirtual=1
43 | Garbage=1
44 | BoundsError=1
45 | ZeroNilCompat=1
46 | StringConstTruncated=1
47 | ForLoopVarVarPar=1
48 | TypedConstVarPar=1
49 | AsgToTypedConst=1
50 | CaseLabelRange=1
51 | ForVariable=1
52 | ConstructingAbstract=1
53 | ComparisonFalse=1
54 | ComparisonTrue=1
55 | ComparingSignedUnsigned=1
56 | CombiningSignedUnsigned=1
57 | UnsupportedConstruct=1
58 | FileOpen=1
59 | FileOpenUnitSrc=1
60 | BadGlobalSymbol=1
61 | DuplicateConstructorDestructor=1
62 | InvalidDirective=1
63 | PackageNoLink=1
64 | PackageThreadVar=1
65 | ImplicitImport=1
66 | HPPEMITIgnored=1
67 | NoRetVal=1
68 | UseBeforeDef=1
69 | ForLoopVarUndef=1
70 | UnitNameMismatch=1
71 | NoCFGFileFound=1
72 | MessageDirective=1
73 | ImplicitVariants=1
74 | UnicodeToLocale=1
75 | LocaleToUnicode=1
76 | ImagebaseMultiple=1
77 | SuspiciousTypecast=1
78 | PrivatePropAccessor=1
79 | UnsafeType=0
80 | UnsafeCode=0
81 | UnsafeCast=0
82 | [Linker]
83 | MapFile=3
84 | OutputObjs=0
85 | ConsoleApp=1
86 | DebugInfo=0
87 | RemoteSymbols=0
88 | MinStackSize=16384
89 | MaxStackSize=1048576
90 | ImageBase=4194304
91 | ExeDescription=
92 | [Directories]
93 | OutputDir=..\build\bin
94 | UnitOutputDir=..\build\dcu
95 | PackageDLLOutputDir=..\build\bin
96 | PackageDCPOutputDir=
97 | SearchPath=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug;.\;..\Source;..\Source\utils
98 | Packages=vcl;rtl;dbrtl;inet;inetdb;dsnap;bdertl;vclx;vcldb;vcldbx;visualclx;visualdbclx;vclactnband;vclshlctrls;vclie;xmlrtl;inetdbbde;inetdbxpress;webdsnap;soaprtl;websnap;adortl;dbexpress;dsnapcon;dbxcds;ibxpress;teeui;teedb;tee;dclOfficeXP;VclNewlyext;JclDeveloperTools;Jcl;JclVcl;JclContainers;madBasic_;madDisAsm_;madExcept_;ZComponent;ZParseSql;ZCore;ZDbc;ZPlain
99 | Conditionals=DEBUG;FastMM
100 | DebugSourceDirs=
101 | UsePackages=0
102 | [Parameters]
103 | RunParams=
104 | HostApplication=
105 | Launcher=
106 | UseLauncher=0
107 | DebugCWD=
108 | [Language]
109 | ActiveLang=
110 | ProjectLang=
111 | RootDir=C:\Program Files\Borland\Delphi7\Bin\
112 | [Version Info]
113 | IncludeVerInfo=0
114 | AutoIncBuild=0
115 | MajorVer=1
116 | MinorVer=0
117 | Release=0
118 | Build=0
119 | Debug=0
120 | PreRelease=0
121 | Special=0
122 | Private=0
123 | DLL=0
124 | Locale=1049
125 | CodePage=1251
126 | [Version Info Keys]
127 | FileVersion=1.0.0.0
128 | [Excluded Packages]
129 | c:\program files\borland\delphi7\Bin\dclindy70.bpl=Internet Direct (Indy) for D7 Property and Component Editors
130 | [HistoryLists\hlConditionals]
131 | Count=3
132 | Item0=Debug;FastMM
133 | Item1=FastMM
134 | Item2=DEBUG
135 | [HistoryLists\hlUnitAliases]
136 | Count=1
137 | Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
138 | [HistoryLists\hlSearchPath]
139 | Count=4
140 | Item0=..\..\source
141 | Item1=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug;.\;..\Source;..\Source\utils
142 | Item2=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug;.\;..\Source
143 | Item3=$(DELPHI)\Lib\Debug;D:\DELPHI~1\JCL\official\JCL-26~1.517\lib\d7\debug;D:\DELPHI~1\JCL\official\JCL-27~1.567\lib\d7\debug
144 | [HistoryLists\hlUnitOutputDirectory]
145 | Count=1
146 | Item0=..\build\dcu
147 | [HistoryLists\hlOutputDirectorry]
148 | Count=1
149 | Item0=..\build\bin
150 | [HistoryLists\hlBPLOutput]
151 | Count=1
152 | Item0=..\build\bin
153 |
--------------------------------------------------------------------------------
/projects/testjsonrpclite.dpr:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Dmitriy S. Sinyavskiy, 2016
3 | //
4 |
5 | //{$DEFINE DUNIT_CONSOLE_MODE}
6 |
7 | program testjsonrpclite;
8 |
9 | {%File '..\source\utils\FastMM4Options.inc'}
10 |
11 | uses
12 | FastMM4,
13 | SysUtils,
14 | TestFramework,
15 | TestExtensions,
16 | GUITestRunner,
17 | TextTestRunner,
18 | testjsonrpc in '..\test\testjsonrpc.pas',
19 | testjsonrpcerrors in '..\test\testjsonrpcerrors.pas',
20 | ujsonrpc2 in '..\source\ujsonrpc2.pas';
21 |
22 | {$IFDEF DUNIT_CONSOLE_MODE}
23 | {$APPTYPE CONSOLE}
24 | {$ELSE}
25 | {$R *.RES}
26 | {$ENDIF}
27 |
28 | begin
29 | {$IFDEF DUNIT_CONSOLE_MODE}
30 | if not FindCmdLineSwitch('Graphic', ['-','/'], True) then
31 | TextTestRunner.RunRegisteredTests(rxbHaltOnFailures)
32 | else
33 | {$ENDIF}
34 | GUITestRunner.RunRegisteredTests;
35 | end.
36 |
--------------------------------------------------------------------------------
/source/ujsonrpc2.pas:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Dmitriy S. Sinyavskiy, 2017
3 | //
4 | unit ujsonrpc2;
5 | {$IFDEF FPC}
6 | {$MODE objfpc}
7 | {$H+} // make string type AnsiString
8 | {$ENDIF}
9 |
10 | interface
11 |
12 | uses
13 | Classes,
14 | SysUtils,
15 | superobject;
16 |
17 | type
18 | IJsonRpcMessage = interface
19 | ['{E9536C8C-5789-4ED1-BAEB-331E6B4CE70A}']
20 | function AsJSON(indent: boolean = false; escape: boolean = true): string;
21 | function AsJsonObject: ISuperObject;
22 | end;
23 |
24 | { TJsonRpcObjectType }
25 |
26 | // Parsed RPC message types
27 | TJsonRpcObjectType = (jotInvalid, jotRequest, jotNotification, jotSuccess,
28 | jotError);
29 |
30 | IJsonRpcParsedMessage = interface
31 | ['{9BC6D534-8EA4-4D5D-9D35-358D717D91DA}']
32 | function GetMessageType: TJsonRpcObjectType;
33 | function GetMessagePayload: IJsonRpcMessage;
34 | end;
35 |
36 | IJsonRpcError = interface
37 | ['{574043CE-CA33-462F-AF52-49C5B63FF58B}']
38 | function GetCode: Integer;
39 | function GetMessage: string;
40 | function GetData: ISuperObject;
41 | function AsJsonObject: ISuperObject;
42 | // props
43 | property Code: Integer read GetCode;
44 | property Message: string read GetMessage;
45 | property Data: ISuperObject read GetData;
46 | end;
47 |
48 | TJsonRpcRequestObject = class;
49 | TJsonRpcNotificationObject = class;
50 | TJsonRpcSuccessObject = class;
51 | TJsonRpcErrorObject = class;
52 | TJsonRpcError = class;
53 |
54 | { TJsonRpcMessage }
55 |
56 | TJsonRpcMessage = class(TInterfacedObject, IJsonRpcMessage)
57 | class function Request(const id: string; const method: string;
58 | params: ISuperObject): TJsonRpcRequestObject;
59 | class function Notification(const method: string;
60 | params: ISuperObject): TJsonRpcNotificationObject; overload;
61 | class function Notification(const method: string):
62 | TJsonRpcNotificationObject;
63 | overload;
64 | class function Success(const id: string;
65 | resultData: ISuperObject): TJsonRpcSuccessObject; overload;
66 | class function Error(const id: string;
67 | errorInfo: IJsonRpcError): TJsonRpcErrorObject; overload;
68 | class function Error(errorInfo: IJsonRpcError): TJsonRpcErrorObject;
69 | overload;
70 | class function Parse(const s: string;
71 | out AParseError: IJsonRpcError): IJsonRpcParsedMessage;
72 | public
73 | function AsJSON(indent: boolean = false; escape: boolean = true): string;
74 | function AsJsonObject: ISuperObject; virtual; abstract;
75 | end;
76 |
77 | { TJsonRpcNotificationObject }
78 |
79 | TJsonRpcNotificationObject = class(TJsonRpcMessage, IJsonRpcMessage)
80 | private
81 | FMethod: string;
82 | FParams: ISuperObject;
83 | public
84 | constructor Create(const AMethod: string; AParams: ISuperObject); overload;
85 | constructor Create(const aMethod: string); overload;
86 | function AsJsonObject: ISuperObject; override;
87 | published
88 | property Method: string read FMethod;
89 | property Params: ISuperObject read FParams;
90 | end;
91 |
92 | { TJsonRpcRequestObject }
93 |
94 | TJsonRpcRequestObject = class(TJsonRpcNotificationObject, IJsonRpcMessage)
95 | private
96 | FID: string;
97 | public
98 | constructor Create(const aID: string; const aMethod: string; aParams:
99 | ISuperObject);
100 | function AsJsonObject: ISuperObject; override;
101 | published
102 | property ID: string read FID;
103 | property Method;
104 | property Params;
105 | end;
106 |
107 | { TJsonRpcSuccessObject }
108 |
109 | TJsonRpcSuccessObject = class(TJsonRpcMessage, IJsonRpcMessage)
110 | private
111 | FID: string;
112 | FResult: ISuperObject;
113 | public
114 | constructor Create(const aID: string; AResult: ISuperObject);
115 | function AsJsonObject: ISuperObject; override;
116 | published
117 | property ID: string read FID;
118 | // Holds Variant type object, can be string, ISuperObject, Int, etc
119 | // Use GetResult.DataType property to detect actual type.
120 | property Result: ISuperObject read FResult;
121 | end;
122 |
123 | { TJsonRpcErrorObject }
124 |
125 | // ErrorObject message contains id and errorInfo
126 | TJsonRpcErrorObject = class(TJsonRpcMessage, IJsonRpcMessage)
127 | private
128 | FErrorInfo: IJsonRpcError;
129 | FID: string;
130 | public
131 | constructor Create(AErrorInfo: IJsonRpcError); overload;
132 | constructor Create(const AID: string; AErrorInfo: IJsonRpcError); overload;
133 | function AsJsonObject: ISuperObject; override;
134 | published
135 | property ID: string read FID;
136 | property ErrorInfo: IJsonRpcError read FErrorInfo;
137 | end;
138 |
139 | { TJsonRpcParsedMessage }
140 |
141 | // Represents parsed result, contains type of parsed message and parsed
142 | // data as one of TJsonRpcRequestObject, TJsonRpcNotificationObject,
143 | // TJsonRpcSuccessObject, TJsonRpcErrorObject
144 | TJsonRpcParsedMessage = class(TInterfacedObject, IJsonRpcParsedMessage)
145 | private
146 | FObjType: TJsonRpcObjectType;
147 | FPayload: IJsonRpcMessage;
148 | public
149 | constructor Create(const objType: TJsonRpcObjectType;
150 | Payload: IJsonRpcMessage);
151 | destructor Destroy; override;
152 | function GetMessageType: TJsonRpcObjectType;
153 | function GetMessagePayload: IJsonRpcMessage;
154 | end;
155 |
156 | { TJsonRpcError }
157 |
158 | // Error information: code, message, data
159 | TJsonRpcError = class(TInterfacedObject, IJsonRpcError)
160 | class function Error(const code: integer; const message: string; data:
161 | ISuperObject): IJsonRpcError; overload;
162 | class function Error(const code: integer; const message: string; dataStr:
163 | string): IJsonRpcError; overload;
164 | class function ParseError(data: string): IJsonRpcError;
165 | class function InvalidRequest(data: ISuperObject): IJsonRpcError; overload;
166 | class function InvalidRequest(data: string): IJsonRpcError; overload;
167 | class function MethodNotFound(data: ISuperObject): IJsonRpcError; overload;
168 | class function MethodNotFound(data: string): IJsonRpcError; overload;
169 | class function InvalidParams(data: ISuperObject): IJsonRpcError; overload;
170 | class function InvalidParams(data: string): IJsonRpcError; overload;
171 | class function InternalError(data: ISuperObject): IJsonRpcError; overload;
172 | class function InternalError(data: string): IJsonRpcError; overload;
173 | private
174 | FCode: Integer;
175 | FData: ISuperObject;
176 | FMessage: string;
177 | public
178 | constructor Create(const code: integer; const message: string); overload;
179 | constructor Create(const code: integer; const message: string;
180 | data: ISuperObject); overload;
181 | constructor Create(const code: integer; const message: string;
182 | data: string); overload;
183 | function GetCode: Integer;
184 | function GetMessage: string;
185 | function GetData: ISuperObject;
186 | function AsJsonObject: ISuperObject;
187 | published
188 | property Code: Integer read GetCode;
189 | property Message: string read GetMessage;
190 | property Data: ISuperObject read GetData;
191 | end;
192 |
193 | const
194 | JSON_RPC_VERSION_2 = '2.0';
195 |
196 | FIELD_JSONRPC = 'jsonrpc';
197 | FIELD_ID = 'id';
198 | FIELD_METHOD = 'method';
199 | FIELD_PARAMS = 'params';
200 | FIELD_RESULT = 'result';
201 | FIELD_ERROR = 'error';
202 | FIELD_ERROR_CODE = 'code';
203 | FIELD_ERROR_MSG = 'message';
204 | FIELD_ERROR_DATA = 'data';
205 |
206 | ERROR_INVALID_JSONRPC_VER =
207 | 'Invalid JSON-RPC Version. Supported JSON-RPC 2.0 only';
208 | ERROR_NO_JSONRPC_FIELD = 'No ''jsonrpc'' field present';
209 | ERROR_NO_ID_FIELD = 'No ''id'' field present';
210 | ERROR_NO_METHOD_FIELD = 'No ''method'' field present';
211 | ERROR_NO_RESULT_FIELD = 'No ''result'' field present';
212 | ERROR_NO_ERROR_FIELD = 'No ''error'' field present';
213 | ERROR_INVALID_REQUEST_ID =
214 | 'Invalid Request ''id'', MUST BE not empty string or integer';
215 | ERROR_INVALID_REQUEST_ID_TYPE =
216 | 'Invalid Request ''id'' data type, it should be string or integer';
217 | ERROR_INVALID_ERROR_ID_TYPE =
218 | 'Invalid Error ''id'' data type, it should be string or integer';
219 | ERROR_INVALID_ERROR_ID =
220 | 'Invalid Error ''id'', MUST BE not empty string, integer or null';
221 | ERROR_INVALID_METHOD_NAME = 'Empty ''method'' field';
222 | ERROR_INVALID_ERROR_OBJ = 'Invalid ''error'' object';
223 | ERROR_INVALID_ERROR_CODE =
224 | 'Invalid ''error.code'', it MUST BE in the range [-32768..-32000]';
225 | ERROR_INVALID_ERROR_MSG = 'Empty ''error.message''';
226 |
227 | PRC_ERR_INVALID_REQUEST = 'Invalid Request';
228 | PRC_ERR_METHOD_NOT_FOUND = 'Method Not Found';
229 | RPC_ERR_INVALID_PARAMS = 'Invalid Params';
230 | RPC_ERR_INTERNAL_ERROR = 'Internal Error';
231 | RPC_ERR_PARSE_ERROR = 'Parse Error';
232 |
233 | CODE_INVALID_REQUEST = -32600;
234 | CODE_METHOD_NOT_FOUND = -32601;
235 | CODE_INVALID_PARAMS = -32602;
236 | CODE_INTERNAL_ERROR = -32603;
237 | CODE_PARSE_ERROR = -32700;
238 |
239 | implementation
240 |
241 | const
242 | S_EMPTY_STR = '';
243 |
244 | { TJsonRpcMessage }
245 |
246 | function TJsonRpcMessage.AsJSON(indent: boolean; escape: boolean): string;
247 | begin
248 | Result := AsJsonObject.AsJSon(indent, escape);
249 | end;
250 |
251 | { TJsonRpcMessage }
252 |
253 | // Creates JSON-RPC 2.0 request object
254 | // @param {String} id
255 | // @param {String} method
256 | // @param {ISuperObject} [params]: optional
257 | // @return {ISuperObject} JsonRpc object
258 |
259 | class function TJsonRpcMessage.Request(const id: string;
260 | const method: string; params: ISuperObject): TJsonRpcRequestObject;
261 | begin
262 | result := TJsonRpcRequestObject.Create(id, method, params);
263 | end;
264 |
265 | // Creates JSON-RPC 2.0 notification object
266 | // @param {String} method
267 | // @param {ISuperObject} [params]
268 | // @return {ISuperObject} JsonRpc object
269 |
270 | class function TJsonRpcMessage.Notification(const method: string;
271 | params: ISuperObject): TJsonRpcNotificationObject;
272 | begin
273 | Result := TJsonRpcNotificationObject.Create(method, params);
274 | end;
275 |
276 | // Creates JSON-RPC 2.0 notification object
277 | // @param {String} method
278 | // @return {ISuperObject} JsonRpc object
279 |
280 | class function TJsonRpcMessage.Notification(const method: string):
281 | TJsonRpcNotificationObject;
282 | begin
283 | result := TJsonRpcMessage.Notification(method, nil);
284 | end;
285 |
286 | // Creates JSON-RPC 2.0 success object
287 | // @param {string} id
288 | // @param {ISuperObject} requestResult
289 | // @return {ISuperObject} JsonRpc object
290 |
291 | class function TJsonRpcMessage.Success(const id: string;
292 | resultData: ISuperObject): TJsonRpcSuccessObject;
293 | begin
294 | result := TJsonRpcSuccessObject.Create(id, resultData);
295 | end;
296 |
297 | // Creates JSON-RPC 2.0 error object
298 | // @param {string} id
299 | // @param {ISuperObject} error
300 | // @return {ISuperObject} JsonRpc object
301 |
302 | class function TJsonRpcMessage.Error(const id: string;
303 | errorInfo: IJsonRpcError): TJsonRpcErrorObject;
304 | begin
305 | result := TJsonRpcErrorObject.Create(id, errorInfo);
306 | end;
307 |
308 | // Creates JSON-RPC 2.0 error object
309 | // @param {ISuperObject} error
310 | // @return {ISuperObject} JsonRpc object
311 |
312 | class function TJsonRpcMessage.Error(errorInfo: IJsonRpcError):
313 | TJsonRpcErrorObject;
314 | begin
315 | result := TJsonRpcErrorObject.Create(errorInfo);
316 | end;
317 |
318 | //
319 | // @return TJsonRpcParsedMessage
320 | //
321 |
322 | // Returns nil if ERROR and AParseError contains error info,
323 | // else IJsonRpcParsedMessage
324 |
325 | class function TJsonRpcMessage.Parse(const s: string;
326 | out AParseError: IJsonRpcError): IJsonRpcParsedMessage;
327 |
328 | // checks if 'id' field present in JSON
329 | function SubIsIdPresent(AJsonObj: ISuperObject): boolean;
330 | begin
331 | Result := AJsonObj.AsObject.Exists(FIELD_ID);
332 | end;
333 |
334 | // Checks if 'id' field present in JSON and has valid data type
335 | // for RPC Request object
336 | function SubIsRequestIdDefValid(AJsonObj: ISuperObject): boolean;
337 | begin
338 | // Request MUST have id value string or integer
339 | Result := SubIsIdPresent(AJsonObj)
340 | and (AJsonObj.O[FIELD_ID].DataType in [stInt, stString]);
341 | end;
342 |
343 | // Checks if 'id' field have valid value
344 | function SubIsRequestIdValueValid(AJsonObj: ISuperObject): Boolean;
345 | begin
346 | Result := SubIsRequestIdDefValid(AJsonObj)
347 | and (Trim(AJsonObj.S[FIELD_ID]) <> S_EMPTY_STR)
348 | end;
349 |
350 | // Checks if 'id' field present in JSON and has valid data type
351 | // for RPC Error Object
352 | function SubIsErrorIdDefValid(AJsonObj: ISuperObject): boolean;
353 | begin
354 | // errors MUST have id=null for Invalid Request, Parse Error
355 | Result := SubIsIdPresent(AJsonObj)
356 | and (AJsonObj.O[FIELD_ID].DataType in [stInt, stString, stNull]);
357 | end;
358 |
359 | // Checks if 'id' field have valid value for RPC Error Object
360 | function SubIsErrorIdValueValid(AJsonObj: ISuperObject): Boolean;
361 | begin
362 | Result := SubIsErrorIdDefValid(AJsonObj)
363 | and (
364 | (Trim(AJsonObj.S[FIELD_ID]) <> S_EMPTY_STR)
365 | or
366 | ObjectIsNull(AJsonObj.O[FIELD_ID])
367 | );
368 | end;
369 |
370 | // Checks if 'method' field present in JSON
371 | function SubIsMethodPresent(AJsonObj: ISuperObject): boolean;
372 | begin
373 | Result := AJsonObj.AsObject.Exists(FIELD_METHOD);
374 | end;
375 |
376 | // Checks if 'method' field has valid data type
377 | function SubIsMethodDefValid(AJsonObj: ISuperObject): boolean;
378 | begin
379 | result := SubIsMethodPresent(AJsonObj)
380 | and (AJsonObj.O[FIELD_METHOD].DataType in [stString]);
381 | end;
382 |
383 | // Checks if 'method' field has valid structure and value
384 | function SubIsMethodValid(AJsonObj: ISuperObject): boolean;
385 | begin
386 | result := SubIsMethodDefValid(AJsonObj)
387 | and (Trim(AJsonObj.S[FIELD_METHOD]) <> S_EMPTY_STR);
388 | end;
389 |
390 | // Checks if 'params' field present in JSON
391 | function SubIsParamsPresent(AJsonObj: ISuperObject): boolean;
392 | begin
393 | Result := AJsonObj.AsObject.Exists(FIELD_PARAMS);
394 | end;
395 |
396 | // Checks if 'params' field has valid structure and data type
397 | function SubIsParamsDefValid(AJsonObj: ISuperObject): boolean;
398 | begin
399 | Result := SubIsParamsPresent(AJsonObj)
400 | and (AJsonObj.O[FIELD_PARAMS].DataType in [stArray, stObject]);
401 | end;
402 |
403 | // Checks if 'result' field present in JSON
404 | function SubIsResultPresent(AJsonObj: ISuperObject): boolean;
405 | begin
406 | Result := AJsonObj.AsObject.Exists(FIELD_RESULT);
407 | end;
408 |
409 | // Checks if 'error' field present in JSON
410 | function SubIsErrorPresent(AJsonObj: ISuperObject): boolean;
411 | begin
412 | Result := AJsonObj.AsObject.Exists(FIELD_ERROR);
413 | end;
414 |
415 | // Checks if RPC Error object has valid strucure
416 | function SubIsErrorObjDefValid(AJsonObj: ISuperObject): boolean;
417 | var
418 | errInfo: ISuperObject;
419 | errCodeDefValid, messageDefValid: boolean;
420 | begin
421 | Result := SubIsErrorPresent(AJsonObj);
422 | errInfo := AJsonObj.O[FIELD_ERROR];
423 | errCodeDefValid := errInfo.AsObject.Exists(FIELD_ERROR_CODE)
424 | and (errInfo.O[FIELD_ERROR_CODE].DataType in [stInt]);
425 | messageDefValid := errInfo.AsObject.Exists(FIELD_ERROR_MSG)
426 | and (errInfo.O[FIELD_ERROR_MSG].DataType in [stString]);
427 | // 'data':any optional
428 | Result := Result and errCodeDefValid and messageDefValid;
429 | end;
430 |
431 | // Checks Error Code in allowed range
432 | function SubIsErrorCodeValid(const ACode: Integer): boolean;
433 | begin
434 | Result := (ACode <= -32000) and (ACode >= -32768);
435 | end;
436 |
437 | // Checks if 'error.message' not empty
438 | function SubIsErrorMessageValid(const AMsg: string): boolean;
439 | begin
440 | Result := (Trim(AMsg) <> S_EMPTY_STR);
441 | end;
442 |
443 | // Detects RPC message type by structure ONLY, no value checks here.
444 | // Do value validation in SubParse* functions.
445 | function SubGetMessageType(AJsonObj: ISuperObject): TJsonRpcObjectType;
446 | var
447 | ItLooksLikeNotification,
448 | ItLooksLikeRequest,
449 | ItLooksLikeSuccess,
450 | ItLooksLikeError: boolean;
451 | begin
452 | Result := jotInvalid;
453 | // MUST have 'method':str and MUST NOT have 'id'
454 | ItLooksLikeNotification := not SubIsIdPresent(AJsonObj)
455 | and SubIsMethodDefValid(AJsonObj);
456 | if ItLooksLikeNotification then
457 | begin
458 | Result := jotNotification;
459 | Exit;
460 | end;
461 | // MUST have 'id':str/int, 'method':str
462 | ItLooksLikeRequest := SubIsRequestIdDefValid(AJsonObj)
463 | and SubIsMethodDefValid(AJsonObj);
464 | if ItLooksLikeRequest then
465 | begin
466 | Result := jotRequest;
467 | Exit;
468 | end;
469 | // MUST have 'id':str/int, 'result':any
470 | ItLooksLikeSuccess := SubIsRequestIdDefValid(AJsonObj)
471 | and SubIsResultPresent(AJsonObj);
472 | if ItLooksLikeSuccess then
473 | begin
474 | Result := jotSuccess;
475 | Exit;
476 | end;
477 | // MUST have 'id':str/int/null, 'error':errorInfo
478 | // where errorInfo = {code:int, message:str, data:any optional}
479 | ItLooksLikeError := SubIsErrorIdDefValid(AJsonObj)
480 | and SubIsErrorObjDefValid(AJsonObj);
481 | if ItLooksLikeError then
482 | begin
483 | Result := jotError;
484 | Exit;
485 | end;
486 | end;
487 |
488 | //
489 | // Parsing Errors detecting functions named SubCheck*
490 | //
491 | // Checks 'jsonrpc' field exists and valid.
492 | // Returns IJsonRpcError if not OK, or nil if no error
493 | function SubCheckHeader(AJsonObj: ISuperObject): IJsonRpcError;
494 | begin
495 | Result := nil;
496 | if not AJsonObj.AsObject.Exists(FIELD_JSONRPC) then
497 | begin
498 | Result := TJsonRpcError.InvalidRequest(SO(ERROR_NO_JSONRPC_FIELD));
499 | Exit;
500 | end;
501 | if AJsonObj.S[FIELD_JSONRPC] <> JSON_RPC_VERSION_2 then
502 | begin
503 | Result := TJsonRpcError.invalidRequest(SO(ERROR_INVALID_JSONRPC_VER));
504 | Exit;
505 | end;
506 | end;
507 |
508 | // Checks 'id' field exists, has corect type and not empty
509 | // for RPC Request Object.
510 | // Returns nil and not empty AFoundId if OK,
511 | // else IJsonRpcError and empty AFoundId.
512 | function SubCheckRequestId(AJsonObj: ISuperObject;
513 | var AFoundId: string): IJsonRpcError;
514 | begin
515 | Result := nil;
516 | // check: 1.present, 2.structure, 3.value
517 | // check: present
518 | if not SubIsIdPresent(AJsonObj) then
519 | begin
520 | Result := TJsonRpcError.InvalidRequest(ERROR_NO_ID_FIELD);
521 | Exit;
522 | end;
523 | AFoundId := AJsonObj.S[FIELD_ID];
524 | // check: structure
525 | if not SubIsRequestIdDefValid(AJsonObj) then
526 | begin
527 | Result := TJsonRpcError.InvalidRequest(ERROR_INVALID_REQUEST_ID_TYPE);
528 | Exit;
529 | end;
530 | // check: value
531 | if not SubIsRequestIdValueValid(AJsonObj) then
532 | begin
533 | Result := TJsonRpcError.InvalidRequest(ERROR_INVALID_REQUEST_ID);
534 | Exit;
535 | end;
536 | end;
537 |
538 | // Checks 'id' field exists, has corect type and not empty or null
539 | // for RPC Error Object.
540 | // Returns nil and not empty AFoundId if OK,
541 | // else TJsonRpcError and empty AFoundId.
542 | function SubCheckErrorId(AJsonObj: ISuperObject;
543 | var AFoundErrorId: ISuperObject): IJsonRpcError;
544 | begin
545 | Result := nil;
546 | if not SubIsIdPresent(AJsonObj) then
547 | begin
548 | Result := TJsonRpcError.InvalidRequest(ERROR_NO_ID_FIELD);
549 | Exit;
550 | end;
551 | AFoundErrorId := AJsonObj.O[FIELD_ID];
552 | if not SubIsErrorIdDefValid(AJsonObj) then
553 | begin
554 | Result := TJsonRpcError.InvalidRequest(ERROR_INVALID_ERROR_ID_TYPE);
555 | Exit;
556 | end;
557 | if not SubIsErrorIdValueValid(AJsonObj) then
558 | begin
559 | Result := TJsonRpcError.InvalidRequest(ERROR_INVALID_ERROR_ID);
560 | Exit;
561 | end;
562 | end;
563 |
564 | // Checks 'method' field exists and not empty.
565 | // Returns nil and not empty AFoundMethod if OK,
566 | // else IJsonRpcError and empty AFoundMethod.
567 | function SubCheckMethod(AJsonObj: ISuperObject;
568 | var AFoundMethod: string): IJsonRpcError;
569 | begin
570 | Result := nil;
571 | if not SubIsMethodPresent(AJsonObj) then
572 | begin
573 | Result := TJsonRpcError.InvalidRequest(ERROR_NO_METHOD_FIELD);
574 | Exit;
575 | end;
576 | AFoundMethod := AJsonObj.S[FIELD_METHOD];
577 | if SubIsMethodValid(AJsonObj) then
578 | Exit;
579 | Result := TJsonRpcError.InvalidRequest(ERROR_INVALID_METHOD_NAME);
580 | end;
581 |
582 | // Checks 'result' field exists, returns IJsonRpcError if not exists
583 | // or nil if no error
584 | function SubCheckResult(AJsonObj: ISuperObject): IJsonRpcError;
585 | begin
586 | Result := nil;
587 | if not SubIsResultPresent(AJsonObj) then
588 | begin
589 | Result := TJsonRpcError.InvalidRequest(ERROR_NO_RESULT_FIELD);
590 | Exit;
591 | end;
592 | end;
593 |
594 | // Checks 'error' field exists and has valid structure.
595 | // Returns IJsonRpcError if not OK, or nil if no error
596 | function SubCheckErrorInfo(AJsonObj: ISuperObject): IJsonRpcError;
597 | var
598 | errObj: ISuperObject;
599 | begin
600 | Result := nil;
601 | if not SubIsErrorPresent(AJsonObj) then
602 | begin
603 | Result := TJsonRpcError.InvalidParams(SO(ERROR_NO_ERROR_FIELD));
604 | Exit;
605 | end;
606 | if not SubIsErrorObjDefValid(AJsonObj) then
607 | begin
608 | Result := TJsonRpcError.InvalidParams(SO(ERROR_INVALID_ERROR_OBJ));
609 | Exit;
610 | end;
611 | if not SubIsErrorIdValueValid(AJsonObj) then
612 | begin
613 | Result := TJsonRpcError.InvalidParams(SO(ERROR_INVALID_ERROR_ID));
614 | Exit;
615 | end;
616 | errObj := AJsonObj.O[FIELD_ERROR];
617 | if not SubIsErrorMessageValid(errObj.S[FIELD_ERROR_MSG]) then
618 | begin
619 | Result := TJsonRpcError.InvalidParams(SO(ERROR_INVALID_ERROR_MSG));
620 | Exit;
621 | end;
622 | if not SubIsErrorCodeValid(errObj.I[FIELD_ERROR_CODE]) then
623 | begin
624 | Result := TJsonRpcError.InvalidParams(SO(ERROR_INVALID_ERROR_CODE));
625 | Exit;
626 | end;
627 | end;
628 |
629 | //
630 | // PARSE RPC OBJECTS FUNCTIONS
631 | //
632 |
633 | // Tries to parse JSON as JSON-RPC NOTIFICATION
634 | // Returns TJsonRpcNotificationObject if OK (AParseError=nil),
635 | // else 'nil' and AParseError contains error information.
636 | function SubParseNotification(AJsonObj: ISuperObject;
637 | out AParseError: IJsonRpcError): IJsonRpcMessage;
638 | var
639 | method: string;
640 | params: ISuperObject;
641 | begin
642 | // If NOTIFICATION there is no ID, 'method' MUST be present,
643 | // 'params' MAY be omitted
644 | params := nil;
645 | AParseError := SubCheckMethod(AJsonObj, method);
646 | if Assigned(AParseError) then
647 | Exit;
648 | // NOTIFICATION FOUND!
649 | params := AJsonObj.O[FIELD_PARAMS];
650 | Result := TJsonRpcMessage.Notification(method, params);
651 | end;
652 |
653 | // Tries to parse JSON as JSON-RPC REQUEST
654 | // Returns TJsonRpcRequestObject if OK (AParseError=nil),
655 | // else 'nil' and AParseError contains error information.
656 | function SubParseRequest(AJsonObj: ISuperObject;
657 | out AParseError: IJsonRpcError): IJsonRpcMessage;
658 | var
659 | id, method: string;
660 | params: ISuperObject;
661 | begin
662 | // In Reqest fields 'ID', 'method' MUST be present,
663 | // 'params' MAY be omitted
664 | AParseError := SubCheckRequestId(AJsonObj, id);
665 | if Assigned(AParseError) then
666 | Exit;
667 | AParseError := SubCheckMethod(AJsonObj, method);
668 | if Assigned(AParseError) then
669 | Exit;
670 | // REQUEST FOUND!
671 | params := AJsonObj.O[FIELD_PARAMS];
672 | Result := TJsonRpcMessage.Request(id, method, params);
673 | end;
674 |
675 | // Tries to parse JSON as JSON-RPC Success Object
676 | // Returns TJsonRpcRequestObject if OK (AParseError=nil),
677 | // else 'nil' and AParseError contains error information.
678 | function SubParseSucess(AJsonObj: ISuperObject;
679 | out AParseError: IJsonRpcError): IJsonRpcMessage;
680 | var
681 | id: string;
682 | resultData: ISuperObject;
683 | begin
684 | // fields 'ID', 'result' MUST be present
685 | AParseError := SubCheckRequestId(AJsonObj, id);
686 | if Assigned(AParseError) then
687 | Exit;
688 | AParseError := SubCheckResult(AJsonObj);
689 | if Assigned(AParseError) then
690 | Exit;
691 | // SUCCESS OBJECT FOUND!
692 | resultData := AJsonObj.O[FIELD_RESULT];
693 | Result := TJsonRpcMessage.Success(id, resultData);
694 | end;
695 |
696 | // Tries to parse JSON as JSON-RPC Error Object
697 | // Returns TJsonRpcRequestObject if OK (AParseError=nil),
698 | // else 'nil' and AParseError contains error information.
699 | function SubParseError(AJsonObj: ISuperObject;
700 | out AParseError: IJsonRpcError): IJsonRpcMessage;
701 | var
702 | id: ISuperObject;
703 | errInfo: ISuperObject;
704 | errorData: IJsonRpcError;
705 | begin
706 | // fields 'ID', 'error' MUST be present
707 | AParseError := SubCheckErrorId(AJsonObj, id);
708 | if Assigned(AParseError) then
709 | Exit;
710 | AParseError := SubCheckErrorInfo(AJsonObj);
711 | if Assigned(AParseError) then
712 | Exit;
713 | // ERROR OBJECT FOUND!
714 | errInfo := AJsonObj.O[FIELD_ERROR];
715 | errorData := TJsonRpcError.Create(errInfo.I[FIELD_ERROR_CODE],
716 | errInfo.S[FIELD_ERROR_MSG], errInfo.O[FIELD_ERROR_DATA]);
717 | if ObjectIsNull(id) then
718 | Result := TJsonRpcMessage.Error(errorData)
719 | else
720 | Result := TJsonRpcMessage.Error(id.AsString, errorData);
721 | end;
722 | var
723 | parsedObj: ISuperObject;
724 | msgType: TJsonRpcObjectType;
725 | parsedMsg: IJsonRpcMessage;
726 | begin
727 | Result := nil;
728 | parsedObj := SO(s);
729 | if not Assigned(parsedObj) then
730 | begin
731 | AParseError := TJsonRpcError.ParseError(s);
732 | Exit;
733 | end;
734 | // try to parse valid json object next
735 | AParseError := SubCheckHeader(parsedObj); // must be freed with Result
736 | if Assigned(AParseError) then
737 | Exit;
738 |
739 | // header valid parse other parts
740 | msgType := SubGetMessageType(parsedObj);
741 | case msgType of
742 | jotNotification: parsedMsg := SubParseNotification(parsedObj, AParseError);
743 | jotRequest: parsedMsg := SubParseRequest(parsedObj, AParseError);
744 | jotSuccess: parsedMsg := SubParseSucess(parsedObj, AParseError);
745 | jotError: parsedMsg := SubParseError(parsedObj, AParseError);
746 | else
747 | AParseError := TJsonRpcError.InvalidRequest(parsedObj);
748 | Exit;
749 | end;
750 | if Assigned(AParseError) then
751 | begin
752 | Result := TJsonRpcParsedMessage.Create(jotInvalid,
753 | TJsonRpcMessage.Error(TJsonRpcError.InvalidRequest(parsedObj)));
754 | Exit;
755 | end;
756 | Result := TJsonRpcParsedMessage.Create(msgType, parsedMsg);
757 | end;
758 |
759 | { TJsonRpcSuccessObject }
760 |
761 | constructor TJsonRpcSuccessObject.Create(const aID: string; AResult:
762 | ISuperObject);
763 | begin
764 | FID := aID;
765 | FResult := AResult;
766 | end;
767 |
768 | function TJsonRpcSuccessObject.AsJsonObject: ISuperObject;
769 | begin
770 | Result := SO();
771 | Result.S[FIELD_ID] := FID;
772 | Result.O[FIELD_RESULT] := FResult.Clone;
773 | end;
774 |
775 | { TJsonRpcErrorObject }
776 |
777 | constructor TJsonRpcErrorObject.Create(AErrorInfo: IJsonRpcError);
778 | begin
779 | FErrorInfo := AErrorInfo;
780 | end;
781 |
782 | constructor TJsonRpcErrorObject.Create(const AID: string;
783 | AErrorInfo: IJsonRpcError);
784 | begin
785 | Create(AErrorInfo);
786 | FID := AID;
787 | end;
788 |
789 | function TJsonRpcErrorObject.AsJsonObject: ISuperObject;
790 | begin
791 | Result := SO();
792 | Result.S[FIELD_ID] := FID;
793 | Result.O[FIELD_ERROR] := ErrorInfo.AsJsonObject;
794 | end;
795 |
796 | { TJsonRpcParsedMessage }
797 |
798 | constructor TJsonRpcParsedMessage.Create(const objType: TJsonRpcObjectType;
799 | Payload: IJsonRpcMessage);
800 | begin
801 | inherited Create();
802 | FObjType := objType;
803 | FPayload := Payload;
804 | end;
805 |
806 | destructor TJsonRpcParsedMessage.Destroy;
807 | begin
808 | inherited Destroy;
809 | end;
810 |
811 | function TJsonRpcParsedMessage.GetMessageType: TJsonRpcObjectType;
812 | begin
813 | result := FObjType;
814 | end;
815 |
816 | function TJsonRpcParsedMessage.GetMessagePayload: IJsonRpcMessage;
817 | begin
818 | result := FPayload;
819 | end;
820 |
821 | { TJsonRpcNotificationObject }
822 |
823 | constructor TJsonRpcNotificationObject.Create(const AMethod: string;
824 | AParams: ISuperObject);
825 | begin
826 | inherited Create();
827 | FMethod := AMethod;
828 | FParams := AParams;
829 | end;
830 |
831 | constructor TJsonRpcNotificationObject.Create(const aMethod: string);
832 | begin
833 | Create(aMethod, nil);
834 | end;
835 |
836 | function TJsonRpcNotificationObject.AsJsonObject: ISuperObject;
837 | begin
838 | Result := SO();
839 | Result.S[FIELD_METHOD] := FMethod;
840 | if Assigned(FParams) then
841 | Result.O[FIELD_PARAMS] := FParams.Clone;
842 | end;
843 |
844 | { TJsonRpcRequestObject }
845 |
846 | constructor TJsonRpcRequestObject.Create(const aID: string;
847 | const aMethod: string; aParams: ISuperObject);
848 | begin
849 | inherited Create(aMethod, aParams);
850 | FID := aID;
851 | end;
852 |
853 | function TJsonRpcRequestObject.AsJsonObject: ISuperObject;
854 | begin
855 | Result := inherited AsJsonObject;
856 | Result.S[FIELD_ID] := FID;
857 | end;
858 |
859 | { TJsonRpcError }
860 |
861 | class function TJsonRpcError.Error(const code: integer; const message: string;
862 | data: ISuperObject): IJsonRpcError;
863 | begin
864 | Result := TJsonRpcError.Create(code, message, data);
865 | end;
866 |
867 | class function TJsonRpcError.Error(const code: integer; const message: string;
868 | dataStr: string): IJsonRpcError;
869 | begin
870 | result := TJsonRpcError.Create(code, message, dataStr);
871 | end;
872 |
873 | class function TJsonRpcError.ParseError(data: string): IJsonRpcError;
874 | begin
875 | result := TJsonRpcError.Create(CODE_PARSE_ERROR, RPC_ERR_PARSE_ERROR, data);
876 | end;
877 |
878 | class function TJsonRpcError.InvalidRequest(data: ISuperObject): IJsonRpcError;
879 | begin
880 | result := TJsonRpcError.Create(CODE_INVALID_REQUEST, PRC_ERR_INVALID_REQUEST,
881 | data);
882 | end;
883 |
884 | class function TJsonRpcError.InvalidRequest(data: string): IJsonRpcError;
885 | begin
886 | result := TJsonRpcError.Create(CODE_INVALID_REQUEST, PRC_ERR_INVALID_REQUEST,
887 | data);
888 | end;
889 |
890 | class function TJsonRpcError.MethodNotFound(data: ISuperObject): IJsonRpcError;
891 | begin
892 | result := TJsonRpcError.Create(CODE_METHOD_NOT_FOUND,
893 | PRC_ERR_METHOD_NOT_FOUND, data);
894 | end;
895 |
896 | class function TJsonRpcError.MethodNotFound(data: string): IJsonRpcError;
897 | begin
898 | result := TJsonRpcError.Create(CODE_METHOD_NOT_FOUND,
899 | PRC_ERR_METHOD_NOT_FOUND, data);
900 | end;
901 |
902 | class function TJsonRpcError.InvalidParams(data: ISuperObject): IJsonRpcError;
903 | begin
904 | result := TJsonRpcError.Create(CODE_INVALID_PARAMS, RPC_ERR_INVALID_PARAMS,
905 | data);
906 | end;
907 |
908 | class function TJsonRpcError.InvalidParams(data: string): IJsonRpcError;
909 | begin
910 | result := TJsonRpcError.Create(CODE_INVALID_PARAMS, RPC_ERR_INVALID_PARAMS,
911 | data);
912 | end;
913 |
914 | class function TJsonRpcError.InternalError(data: ISuperObject): IJsonRpcError;
915 | begin
916 | result := TJsonRpcError.Create(CODE_INTERNAL_ERROR, RPC_ERR_INTERNAL_ERROR,
917 | data);
918 | end;
919 |
920 | class function TJsonRpcError.InternalError(data: string): IJsonRpcError;
921 | begin
922 | result := TJsonRpcError.Create(CODE_INTERNAL_ERROR, RPC_ERR_INTERNAL_ERROR,
923 | data);
924 | end;
925 |
926 | constructor TJsonRpcError.Create(const code: integer;
927 | const message: string);
928 | begin
929 | FCode := code;
930 | FMessage := message;
931 | end;
932 |
933 | function TJsonRpcError.GetCode: Integer;
934 | begin
935 | Result := FCode;
936 | end;
937 |
938 | function TJsonRpcError.GetData: ISuperObject;
939 | begin
940 | Result := FData;
941 | end;
942 |
943 | function TJsonRpcError.GetMessage: string;
944 | begin
945 | Result := FMessage;
946 | end;
947 |
948 | function TJsonRpcError.AsJsonObject: ISuperObject;
949 | begin
950 | Result := SO();
951 | Result.I[FIELD_ERROR_CODE] := Code;
952 | Result.S[FIELD_ERROR_MSG] := Message;
953 | if Assigned(Data) then
954 | Result.O[FIELD_ERROR_DATA] := Data.Clone;
955 | end;
956 |
957 | { TJsonRpcError }
958 |
959 | constructor TJsonRpcError.Create(const code: integer;
960 | const message: string; data: ISuperObject);
961 | begin
962 | Create(code, message);
963 | FData := data;
964 | end;
965 |
966 | constructor TJsonRpcError.Create(const code: integer;
967 | const message: string; data: string);
968 | begin
969 | Create(code, message, SO(data));
970 | end;
971 |
972 | end.
973 |
974 |
--------------------------------------------------------------------------------
/source/utils/FastMM4.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/source/utils/FastMM4.pas
--------------------------------------------------------------------------------
/source/utils/FastMM4Messages.pas:
--------------------------------------------------------------------------------
1 | {
2 |
3 | Fast Memory Manager: Messages
4 |
5 | English translation by Pierre le Riche.
6 |
7 | }
8 |
9 | unit FastMM4Messages;
10 |
11 | interface
12 |
13 | {$Include FastMM4Options.inc}
14 |
15 | const
16 | {The name of the debug info support DLL}
17 | FullDebugModeLibraryName32Bit = 'FastMM_FullDebugMode.dll';
18 | FullDebugModeLibraryName64Bit = 'FastMM_FullDebugMode64.dll';
19 | {Event log strings}
20 | LogFileExtension = '_MemoryManager_EventLog.txt'#0;
21 | CRLF = #13#10;
22 | EventSeparator = '--------------------------------';
23 | {Class name messages}
24 | UnknownClassNameMsg = 'Unknown';
25 | {Memory dump message}
26 | MemoryDumpMsg = #13#10#13#10'Current memory dump of 256 bytes starting at pointer address ';
27 | {Block Error Messages}
28 | BlockScanLogHeader = 'Allocated block logged by LogAllocatedBlocksToFile. The size is: ';
29 | ErrorMsgHeader = 'FastMM has detected an error during a ';
30 | GetMemMsg = 'GetMem';
31 | FreeMemMsg = 'FreeMem';
32 | ReallocMemMsg = 'ReallocMem';
33 | BlockCheckMsg = 'free block scan';
34 | OperationMsg = ' operation. ';
35 | BlockHeaderCorruptedMsg = 'The block header has been corrupted. ';
36 | BlockFooterCorruptedMsg = 'The block footer has been corrupted. ';
37 | FreeModifiedErrorMsg = 'FastMM detected that a block has been modified after being freed. ';
38 | FreeModifiedDetailMsg = #13#10#13#10'Modified byte offsets (and lengths): ';
39 | DoubleFreeErrorMsg = 'An attempt has been made to free/reallocate an unallocated block.';
40 | WrongMMFreeErrorMsg = 'An attempt has been made to free/reallocate a block that was allocated through a different FastMM instance. Check your memory manager sharing settings.';
41 | PreviousBlockSizeMsg = #13#10#13#10'The previous block size was: ';
42 | CurrentBlockSizeMsg = #13#10#13#10'The block size is: ';
43 | PreviousObjectClassMsg = #13#10#13#10'The block was previously used for an object of class: ';
44 | CurrentObjectClassMsg = #13#10#13#10'The block is currently used for an object of class: ';
45 | PreviousAllocationGroupMsg = #13#10#13#10'The allocation group was: ';
46 | PreviousAllocationNumberMsg = #13#10#13#10'The allocation number was: ';
47 | CurrentAllocationGroupMsg = #13#10#13#10'The allocation group is: ';
48 | CurrentAllocationNumberMsg = #13#10#13#10'The allocation number is: ';
49 | BlockErrorMsgTitle = 'Memory Error Detected';
50 | VirtualMethodErrorHeader = 'FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.';
51 | InterfaceErrorHeader = 'FastMM has detected an attempt to use an interface of a freed object. An access violation will now be raised in order to abort the current operation.';
52 | BlockHeaderCorruptedNoHistoryMsg = ' Unfortunately the block header has been corrupted so no history is available.';
53 | FreedObjectClassMsg = #13#10#13#10'Freed object class: ';
54 | VirtualMethodName = #13#10#13#10'Virtual method: ';
55 | VirtualMethodOffset = 'Offset +';
56 | VirtualMethodAddress = #13#10#13#10'Virtual method address: ';
57 | {Stack trace messages}
58 | CurrentThreadIDMsg = #13#10#13#10'The current thread ID is 0x';
59 | CurrentStackTraceMsg = ', and the stack trace (return addresses) leading to this error is:';
60 | ThreadIDPrevAllocMsg = #13#10#13#10'This block was previously allocated by thread 0x';
61 | ThreadIDAtAllocMsg = #13#10#13#10'This block was allocated by thread 0x';
62 | ThreadIDAtFreeMsg = #13#10#13#10'The block was previously freed by thread 0x';
63 | ThreadIDAtObjectAllocMsg = #13#10#13#10'The object was allocated by thread 0x';
64 | ThreadIDAtObjectFreeMsg = #13#10#13#10'The object was subsequently freed by thread 0x';
65 | StackTraceMsg = ', and the stack trace (return addresses) at the time was:';
66 | {Installation Messages}
67 | AlreadyInstalledMsg = 'FastMM4 is already installed.';
68 | AlreadyInstalledTitle = 'Already installed.';
69 | OtherMMInstalledMsg = 'FastMM4 cannot be installed since another third party memory '
70 | + 'manager has already installed itself.'#13#10'If you want to use FastMM4, '
71 | + 'please make sure that FastMM4.pas is the very first unit in the "uses"'
72 | + #13#10'section of your project''s .dpr file.';
73 | OtherMMInstalledTitle = 'Cannot install FastMM4 - Another memory manager is already installed';
74 | MemoryAllocatedMsg = 'FastMM4 cannot install since memory has already been '
75 | + 'allocated through the default memory manager.'#13#10'FastMM4.pas MUST '
76 | + 'be the first unit in your project''s .dpr file, otherwise memory may '
77 | + 'be allocated'#13#10'through the default memory manager before FastMM4 '
78 | + 'gains control. '#13#10#13#10'If you are using an exception trapper '
79 | + 'like MadExcept (or any tool that modifies the unit initialization '
80 | + 'order),'#13#10'go into its configuration page and ensure that the '
81 | + 'FastMM4.pas unit is initialized before any other unit.';
82 | MemoryAllocatedTitle = 'Cannot install FastMM4 - Memory has already been allocated';
83 | {Leak checking messages}
84 | LeakLogHeader = 'A memory block has been leaked. The size is: ';
85 | LeakMessageHeader = 'This application has leaked memory. ';
86 | SmallLeakDetail = 'The small block leaks are'
87 | {$ifdef HideExpectedLeaksRegisteredByPointer}
88 | + ' (excluding expected leaks registered by pointer)'
89 | {$endif}
90 | + ':'#13#10;
91 | LargeLeakDetail = 'The sizes of leaked medium and large blocks are'
92 | {$ifdef HideExpectedLeaksRegisteredByPointer}
93 | + ' (excluding expected leaks registered by pointer)'
94 | {$endif}
95 | + ': ';
96 | BytesMessage = ' bytes: ';
97 | AnsiStringBlockMessage = 'AnsiString';
98 | UnicodeStringBlockMessage = 'UnicodeString';
99 | LeakMessageFooter = #13#10
100 | {$ifndef HideMemoryLeakHintMessage}
101 | + #13#10'Note: '
102 | {$ifdef RequireIDEPresenceForLeakReporting}
103 | + 'This memory leak check is only performed if Delphi is currently running on the same computer. '
104 | {$endif}
105 | {$ifdef FullDebugMode}
106 | {$ifdef LogMemoryLeakDetailToFile}
107 | + 'Memory leak detail is logged to a text file in the same folder as this application. '
108 | {$else}
109 | + 'Enable the "LogMemoryLeakDetailToFile" to obtain a log file containing detail on memory leaks. '
110 | {$endif}
111 | {$else}
112 | + 'To obtain a log file containing detail on memory leaks, enable the "FullDebugMode" and "LogMemoryLeakDetailToFile" conditional defines. '
113 | {$endif}
114 | + 'To disable this memory leak check, undefine "EnableMemoryLeakReporting".'#13#10
115 | {$endif}
116 | + #0;
117 | LeakMessageTitle = 'Memory Leak Detected';
118 | {$ifdef UseOutputDebugString}
119 | FastMMInstallMsg = 'FastMM has been installed.';
120 | FastMMInstallSharedMsg = 'Sharing an existing instance of FastMM.';
121 | FastMMUninstallMsg = 'FastMM has been uninstalled.';
122 | FastMMUninstallSharedMsg = 'Stopped sharing an existing instance of FastMM.';
123 | {$endif}
124 | {$ifdef DetectMMOperationsAfterUninstall}
125 | InvalidOperationTitle = 'MM Operation after uninstall.';
126 | InvalidGetMemMsg = 'FastMM has detected a GetMem call after FastMM was uninstalled.';
127 | InvalidFreeMemMsg = 'FastMM has detected a FreeMem call after FastMM was uninstalled.';
128 | InvalidReallocMemMsg = 'FastMM has detected a ReallocMem call after FastMM was uninstalled.';
129 | InvalidAllocMemMsg = 'FastMM has detected an AllocMem call after FastMM was uninstalled.';
130 | {$endif}
131 |
132 | implementation
133 |
134 | end.
135 |
136 |
--------------------------------------------------------------------------------
/source/utils/FastMM4Messages_ru.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r3code/pascal-jsonrpc-lite-2/f8ad694cbd2deef6bd8ae8d5378e698edeae2484/source/utils/FastMM4Messages_ru.pas
--------------------------------------------------------------------------------
/source/utils/FastMM4Options.inc:
--------------------------------------------------------------------------------
1 | {
2 |
3 | Fast Memory Manager: Options Include File
4 |
5 | Set the default options for FastMM here.
6 |
7 | }
8 |
9 | {---------------------------Miscellaneous Options-----------------------------}
10 |
11 | {Enable this define to align all blocks on 16 byte boundaries so aligned SSE
12 | instructions can be used safely. If this option is disabled then some of the
13 | smallest block sizes will be 8-byte aligned instead which may result in a
14 | reduction in memory usage. Medium and large blocks are always 16-byte aligned
15 | irrespective of this setting.}
16 | {.$define Align16Bytes}
17 |
18 | {Enable to use faster fixed-size move routines when upsizing small blocks.
19 | These routines are much faster than the Borland RTL move procedure since they
20 | are optimized to move a fixed number of bytes. This option may be used
21 | together with the FastMove library for even better performance.}
22 | {$define UseCustomFixedSizeMoveRoutines}
23 |
24 | {Enable this option to use an optimized procedure for moving a memory block of
25 | an arbitrary size. Disable this option when using the Fastcode move
26 | ("FastMove") library. Using the Fastcode move library allows your whole
27 | application to gain from faster move routines, not just the memory manager. It
28 | is thus recommended that you use the Fastcode move library in conjunction with
29 | this memory manager and disable this option.}
30 | {$define UseCustomVariableSizeMoveRoutines}
31 |
32 | {Enable this option to only install FastMM as the memory manager when the
33 | application is running inside the Delphi IDE. This is useful when you want
34 | to deploy the same EXE that you use for testing, but only want the debugging
35 | features active on development machines. When this option is enabled and
36 | the application is not being run inside the IDE debugger, then the default
37 | Delphi memory manager will be used (which, since Delphi 2006, is FastMM
38 | without FullDebugMode.}
39 | {.$define InstallOnlyIfRunningInIDE}
40 |
41 | {Due to QC#14070 ("Delphi IDE attempts to free memory after the shutdown code
42 | of borlndmm.dll has been called"), FastMM cannot be uninstalled safely when
43 | used inside a replacement borlndmm.dll for the IDE. Setting this option will
44 | circumvent this problem by never uninstalling the memory manager.}
45 | {.$define NeverUninstall}
46 |
47 | {Set this option when you use runtime packages in this application or library.
48 | This will automatically set the "AssumeMultiThreaded" option. Note that you
49 | have to ensure that FastMM is finalized after all live pointers have been
50 | freed - failure to do so will result in a large leak report followed by a lot
51 | of A/Vs. (See the FAQ for more detail.) You may have to combine this option
52 | with the NeverUninstall option.}
53 | {.$define UseRuntimePackages}
54 |
55 | {-----------------------Concurrency Management Options------------------------}
56 |
57 | {Enable to always assume that the application is multithreaded. Enabling this
58 | option will cause a significant performance hit with single threaded
59 | applications. Enable if you are using multi-threaded third party tools that do
60 | not properly set the IsMultiThread variable. Also set this option if you are
61 | going to share this memory manager between a single threaded application and a
62 | multi-threaded DLL.}
63 | {.$define AssumeMultiThreaded}
64 |
65 | {Enable this option to not call Sleep when a thread contention occurs. This
66 | option will improve performance if the ratio of the number of active threads
67 | to the number of CPU cores is low (typically < 2). With this option set a
68 | thread will usually enter a "busy waiting" loop instead of relinquishing its
69 | timeslice when a thread contention occurs, unless UseSwitchToThread is
70 | also defined (see below) in which case it will call SwitchToThread instead of
71 | Sleep.}
72 | {.$define NeverSleepOnThreadContention}
73 |
74 | {Set this option to call SwitchToThread instead of sitting in a "busy waiting"
75 | loop when a thread contention occurs. This is used in conjunction with the
76 | NeverSleepOnThreadContention option, and has no effect unless
77 | NeverSleepOnThreadContention is also defined. This option may improve
78 | performance with many CPU cores and/or threads of different priorities. Note
79 | that the SwitchToThread API call is only available on Windows 2000 and later.}
80 | {.$define UseSwitchToThread}
81 |
82 | {-----------------------------Debugging Options-------------------------------}
83 |
84 | {Enable this option to suppress the generation of debug info for the
85 | FastMM4.pas unit. This will prevent the integrated debugger from stepping into
86 | the memory manager code.}
87 | {.$define NoDebugInfo}
88 |
89 | {Enable this option to suppress the display of all message dialogs. This is
90 | useful in service applications that should not be interrupted.}
91 | {.$define NoMessageBoxes}
92 |
93 | {Set this option to use the Windows API OutputDebugString procedure to output
94 | debug strings on startup/shutdown and when errors occur.}
95 | {.$define UseOutputDebugString}
96 |
97 | {Set this option to use the assembly language version which is faster than the
98 | pascal version. Disable only for debugging purposes. Setting the
99 | CheckHeapForCorruption option automatically disables this option.}
100 | {$define ASMVersion}
101 |
102 | {FastMM always catches attempts to free the same memory block twice, however it
103 | can also check for corruption of the memory heap (typically due to the user
104 | program overwriting the bounds of allocated memory). These checks are
105 | expensive, and this option should thus only be used for debugging purposes.
106 | If this option is set then the ASMVersion option is automatically disabled.}
107 | {.$define CheckHeapForCorruption}
108 |
109 | {Enable this option to catch attempts to perform MM operations after FastMM has
110 | been uninstalled. With this option set when FastMM is uninstalled it will not
111 | install the previous MM, but instead a dummy MM handler that throws an error
112 | if any MM operation is attempted. This will catch attempts to use the MM
113 | after FastMM has been uninstalled.}
114 | {$define DetectMMOperationsAfterUninstall}
115 |
116 | {Set the following option to do extensive checking of all memory blocks. All
117 | blocks are padded with both a header and trailer that are used to verify the
118 | integrity of the heap. Freed blocks are also cleared to to ensure that they
119 | cannot be reused after being freed. This option slows down memory operations
120 | dramatically and should only be used to debug an application that is
121 | overwriting memory or reusing freed pointers. Setting this option
122 | automatically enables CheckHeapForCorruption and disables ASMVersion.
123 | Very important: If you enable this option your application will require the
124 | FastMM_FullDebugMode.dll library. If this library is not available you will
125 | get an error on startup.}
126 | {.$define FullDebugMode}
127 |
128 | {Set this option to perform "raw" stack traces, i.e. check all entries on the
129 | stack for valid return addresses. Note that this is significantly slower
130 | than using the stack frame tracing method, but is usually more complete. Has
131 | no effect unless FullDebugMode is enabled}
132 | {$define RawStackTraces}
133 |
134 | {Set this option to check for user code that uses an interface of a freed
135 | object. Note that this will disable the checking of blocks modified after
136 | being freed (the two are not compatible). This option has no effect if
137 | FullDebugMode is not also enabled.}
138 | {.$define CatchUseOfFreedInterfaces}
139 |
140 | {Set this option to log all errors to a text file in the same folder as the
141 | application. Memory errors (with the FullDebugMode option set) will be
142 | appended to the log file. Has no effect if "FullDebugMode" is not set.}
143 | {$define LogErrorsToFile}
144 |
145 | {Set this option to log all memory leaks to a text file in the same folder as
146 | the application. Memory leak reports (with the FullDebugMode option set)
147 | will be appended to the log file. Has no effect if "LogErrorsToFile" and
148 | "FullDebugMode" are not also set. Note that usually all leaks are always
149 | logged, even if they are "expected" leaks registered through
150 | AddExpectedMemoryLeaks. Expected leaks registered by pointer may be excluded
151 | through the HideExpectedLeaksRegisteredByPointer option.}
152 | {$define LogMemoryLeakDetailToFile}
153 |
154 | {Deletes the error log file on startup. No effect if LogErrorsToFile is not
155 | also set.}
156 | {.$define ClearLogFileOnStartup}
157 |
158 | {Loads the FASTMM_FullDebugMode.dll dynamically. If the DLL cannot be found
159 | then stack traces will not be available. Note that this may cause problems
160 | due to a changed DLL unload order when sharing the memory manager. Use with
161 | care.}
162 | {.$define LoadDebugDLLDynamically}
163 |
164 | {.$define DoNotInstallIfDLLMissing}
165 | {If the FastMM_FullDebugMode.dll file is not available then FastMM will not
166 | install itself. No effect unless FullDebugMode and LoadDebugDLLDynamically
167 | are also defined.}
168 |
169 | {FastMM usually allocates large blocks from the topmost available address and
170 | medium and small blocks from the lowest available address (This reduces
171 | fragmentation somewhat). With this option set all blocks are always
172 | allocated from the highest available address. If the process has a >2GB
173 | address space and contains bad pointer arithmetic code, this option should
174 | help to catch those errors sooner.}
175 | {$define AlwaysAllocateTopDown}
176 |
177 | {Disables the logging of memory dumps together with the other detail for
178 | memory errors.}
179 | {.$define DisableLoggingOfMemoryDumps}
180 |
181 | {If FastMM encounters a problem with a memory block inside the FullDebugMode
182 | FreeMem handler then an "invalid pointer operation" exception will usually
183 | be raised. If the FreeMem occurs while another exception is being handled
184 | (perhaps in the try.. finally code) then the original exception will be
185 | lost. With this option set FastMM will ignore errors inside FreeMem when an
186 | exception is being handled, thus allowing the original exception to
187 | propagate.}
188 | {$define SuppressFreeMemErrorsInsideException}
189 |
190 | {Adds support for notification of memory manager events in FullDebugMode.
191 | With this define set, the application may assign the OnDebugGetMemFinish,
192 | OnDebugFreeMemStart, etc. callbacks in order to be notified when the
193 | particular memory manager event occurs.}
194 | {.$define FullDebugModeCallBacks}
195 |
196 | {---------------------------Memory Leak Reporting-----------------------------}
197 |
198 | {Set this option to enable reporting of memory leaks. Combine it with the two
199 | options below for further fine-tuning.}
200 | {$define EnableMemoryLeakReporting}
201 |
202 | {Set this option to suppress the display and logging of expected memory leaks
203 | that were registered by pointer. Leaks registered by size or class are often
204 | ambiguous, so these expected leaks are always logged to file (in
205 | FullDebugMode with the LogMemoryLeakDetailToFile option set) and are never
206 | hidden from the leak display if there are more leaks than are expected.}
207 | {$define HideExpectedLeaksRegisteredByPointer}
208 |
209 | {Set this option to require the presence of the Delphi IDE to report memory
210 | leaks. This option has no effect if the option "EnableMemoryLeakReporting"
211 | is not also set.}
212 | {.$define RequireIDEPresenceForLeakReporting}
213 |
214 | {Set this option to require the program to be run inside the IDE debugger to
215 | report memory leaks. This option has no effect if the option
216 | "EnableMemoryLeakReporting" is not also set. Note that this option does not
217 | work with libraries, only EXE projects.}
218 | {$define RequireDebuggerPresenceForLeakReporting}
219 |
220 | {Set this option to require the presence of debug info ($D+ option) in the
221 | compiled unit to perform memory leak checking. This option has no effect if
222 | the option "EnableMemoryLeakReporting" is not also set.}
223 | {.$define RequireDebugInfoForLeakReporting}
224 |
225 | {Set this option to enable manual control of the memory leak report. When
226 | this option is set the ReportMemoryLeaksOnShutdown variable (default = false)
227 | may be changed to select whether leak reporting should be done or not. When
228 | this option is selected then both the variable must be set to true and the
229 | other leak checking options must be applicable for the leak checking to be
230 | done.}
231 | (* DUnitMemoryLearReporting
232 | https://stackoverflow.com/a/685988/469898
233 | You have to build your DUnit GUI-testrunner with the FASTMM and
234 | ManualLeakReportingControl directive. This will enable the memoryleak items
235 | (Take a look in GUITestRunner.pas)
236 | *)
237 | {$define ManualLeakReportingControl}
238 |
239 | {Set this option to disable the display of the hint below the memory leak
240 | message.}
241 | {.$define HideMemoryLeakHintMessage}
242 |
243 | {--------------------------Instruction Set Options----------------------------}
244 |
245 | {Set this option to enable the use of MMX instructions. Disabling this option
246 | will result in a slight performance hit, but will enable compatibility with
247 | AMD K5, Pentium I and earlier CPUs. MMX is currently only used in the variable
248 | size move routines, so if UseCustomVariableSizeMoveRoutines is not set then
249 | this option has no effect.}
250 | {.$define EnableMMX}
251 |
252 | {Set this option to force the use of MMX instructions without checking
253 | whether the CPU supports it. If this option is disabled then the CPU will be
254 | checked for compatibility first, and if MMX is not supported it will fall
255 | back to the FPU move code. Has no effect unless EnableMMX is also set.}
256 | {$define ForceMMX}
257 |
258 | {-----------------------Memory Manager Sharing Options------------------------}
259 |
260 | {Allow sharing of the memory manager between a main application and DLLs that
261 | were also compiled with FastMM. This allows you to pass dynamic arrays and
262 | long strings to DLL functions provided both are compiled to use FastMM.
263 | Sharing will only work if the library that is supposed to share the memory
264 | manager was compiled with the "AttemptToUseSharedMM" option set. Note that if
265 | the main application is single threaded and the DLL is multi-threaded that you
266 | have to set the IsMultiThread variable in the main application to true or it
267 | will crash when a thread contention occurs. Note that statically linked DLL
268 | files are initialized before the main application, so the main application may
269 | well end up sharing a statically loaded DLL's memory manager and not the other
270 | way around. }
271 | {.$define ShareMM}
272 |
273 | {Allow sharing of the memory manager by a DLL with other DLLs (or the main
274 | application if this is a statically loaded DLL) that were also compiled with
275 | FastMM. Set this option with care in dynamically loaded DLLs, because if the
276 | DLL that is sharing its MM is unloaded and any other DLL is still sharing
277 | the MM then the application will crash. This setting is only relevant for
278 | DLL libraries and requires ShareMM to also be set to have any effect.
279 | Sharing will only work if the library that is supposed to share the memory
280 | manager was compiled with the "AttemptToUseSharedMM" option set. Note that
281 | if DLLs are statically linked then they will be initialized before the main
282 | application and then the DLL will in fact share its MM with the main
283 | application. This option has no effect unless ShareMM is also set.}
284 | {.$define ShareMMIfLibrary}
285 |
286 | {Define this to attempt to share the MM of the main application or other loaded
287 | DLLs in the same process that were compiled with ShareMM set. When sharing a
288 | memory manager, memory leaks caused by the sharer will not be freed
289 | automatically. Take into account that statically linked DLLs are initialized
290 | before the main application, so set the sharing options accordingly.}
291 | {.$define AttemptToUseSharedMM}
292 |
293 | {Define this to enable backward compatibility for the memory manager sharing
294 | mechanism used by Delphi 2006 and 2007, as well as older FastMM versions.}
295 | {$define EnableBackwardCompatibleMMSharing}
296 |
297 | {-----------------------Security Options------------------------}
298 |
299 | {Windows clears physical memory before reusing it in another process. However,
300 | it is not known how quickly this clearing is performed, so it is conceivable
301 | that confidential data may linger in physical memory longer than absolutely
302 | necessary. If you're paranoid about this kind of thing, enable this option to
303 | clear all freed memory before returning it to the operating system. Note that
304 | this incurs a noticeable performance hit.}
305 | {.$define ClearMemoryBeforeReturningToOS}
306 |
307 | {With this option enabled freed memory will immediately be cleared inside the
308 | FreeMem routine. This incurs a big performance hit, but may be worthwhile for
309 | additional peace of mind when working with highly sensitive data. This option
310 | supersedes the ClearMemoryBeforeReturningToOS option.}
311 | {.$define AlwaysClearFreedMemory}
312 |
313 | {--------------------------------Option Grouping------------------------------}
314 |
315 | {Enabling this option enables FullDebugMode, InstallOnlyIfRunningInIDE and
316 | LoadDebugDLLDynamically. Consequently, FastMM will install itself in
317 | FullDebugMode if the application is being debugged inside the Delphi IDE.
318 | Otherwise the default Delphi memory manager will be used (which is equivalent
319 | to the non-FullDebugMode FastMM since Delphi 2006.)}
320 | {.$define FullDebugModeInIDE}
321 |
322 | {Combines the FullDebugMode, LoadDebugDLLDynamically and
323 | DoNotInstallIfDLLMissing options. Consequently FastMM will only be installed
324 | (In FullDebugMode) when the FastMM_FullDebugMode.dll file is available. This
325 | is useful when the same executable will be distributed for both debugging as
326 | well as deployment.}
327 | {.$define FullDebugModeWhenDLLAvailable}
328 |
329 | {Group the options you use for release and debug versions below}
330 | {$ifdef Release}
331 | {Specify the options you use for release versions below}
332 | {$undef FullDebugMode}
333 | {$undef CheckHeapForCorruption}
334 | {$define ASMVersion}
335 | {$undef EnableMemoryLeakReporting}
336 | {$undef UseOutputDebugString}
337 | {$else}
338 | {Specify the options you use for debugging below}
339 | {$define FullDebugMode}
340 | {$define EnableMemoryLeakReporting}
341 | {$define LogMemoryLeakDetailToFile}
342 | {$define UseOutputDebugString}
343 | {$endif}
344 |
345 | {--------------------Compilation Options For borlndmm.dll---------------------}
346 | {If you're compiling the replacement borlndmm.dll, set the defines below
347 | for the kind of dll you require.}
348 |
349 | {Set this option when compiling the borlndmm.dll}
350 | {.$define borlndmmdll}
351 |
352 | {Set this option if the dll will be used by the Delphi IDE}
353 | {.$define dllforide}
354 |
355 | {Set this option if you're compiling a debug dll}
356 | {.$define debugdll}
357 |
358 | {Do not change anything below this line}
359 | {$ifdef borlndmmdll}
360 | {$define AssumeMultiThreaded}
361 | {$undef HideExpectedLeaksRegisteredByPointer}
362 | {$undef RequireDebuggerPresenceForLeakReporting}
363 | {$undef RequireDebugInfoForLeakReporting}
364 | {$define DetectMMOperationsAfterUninstall}
365 | {$undef ManualLeakReportingControl}
366 | {$undef ShareMM}
367 | {$undef AttemptToUseSharedMM}
368 | {$ifdef dllforide}
369 | {$define NeverUninstall}
370 | {$define HideMemoryLeakHintMessage}
371 | {$undef RequireIDEPresenceForLeakReporting}
372 | {$ifndef debugdll}
373 | {$undef EnableMemoryLeakReporting}
374 | {$endif}
375 | {$else}
376 | {$define EnableMemoryLeakReporting}
377 | {$undef NeverUninstall}
378 | {$undef HideMemoryLeakHintMessage}
379 | {$define RequireIDEPresenceForLeakReporting}
380 | {$endif}
381 | {$ifdef debugdll}
382 | {$define FullDebugMode}
383 | {$define RawStackTraces}
384 | {$undef CatchUseOfFreedInterfaces}
385 | {$define LogErrorsToFile}
386 | {$define LogMemoryLeakDetailToFile}
387 | {$undef ClearLogFileOnStartup}
388 | {$else}
389 | {$undef FullDebugMode}
390 | {$endif}
391 | {$endif}
392 |
393 | {Move BCB related definitions here, because CB2006/CB2007 can build borlndmm.dll
394 | for tracing memory leaks in BCB applications with "Build with Dynamic RTL"
395 | switched on}
396 | {------------------------------Patch BCB Terminate----------------------------}
397 | {To enable the patching for BCB to make uninstallation and leak reporting
398 | possible, you may need to add "BCB" definition
399 | in "Project Options->Pascal/Delphi Compiler->Defines".
400 | (Thanks to JiYuan Xie for implementing this.)}
401 |
402 | {$ifdef BCB}
403 | {$ifdef CheckHeapForCorruption}
404 | {$define PatchBCBTerminate}
405 | {$else}
406 | {$ifdef DetectMMOperationsAfterUninstall}
407 | {$define PatchBCBTerminate}
408 | {$else}
409 | {$ifdef EnableMemoryLeakReporting}
410 | {$define PatchBCBTerminate}
411 | {$endif}
412 | {$endif}
413 | {$endif}
414 |
415 | {$ifdef PatchBCBTerminate}
416 | {$define CheckCppObjectType}
417 | {$undef CheckCppObjectTypeEnabled}
418 |
419 | {$ifdef CheckCppObjectType}
420 | {$define CheckCppObjectTypeEnabled}
421 | {$endif}
422 |
423 | {Turn off "CheckCppObjectTypeEnabled" option if neither "CheckHeapForCorruption"
424 | option or "EnableMemoryLeakReporting" option were defined.}
425 | {$ifdef CheckHeapForCorruption}
426 | {$else}
427 | {$ifdef EnableMemoryLeakReporting}
428 | {$else}
429 | {$undef CheckCppObjectTypeEnabled}
430 | {$endif}
431 | {$endif}
432 | {$endif}
433 | {$endif}
434 |
--------------------------------------------------------------------------------
/test/testjsonrpc.pas:
--------------------------------------------------------------------------------
1 |
2 | unit testjsonrpc;
3 |
4 | interface
5 |
6 | uses
7 | Windows, SysUtils, Classes, TestFramework, TestExtensions, ujsonrpc2;
8 |
9 | type
10 | TTestJsonRpc = class(TTestCase)
11 | private
12 | function GetMessageTypeName(t: TJsonRpcObjectType): string;
13 | protected
14 | procedure SetUp; override;
15 | procedure TearDown; override;
16 |
17 | published
18 | procedure TestParseRequestOK;
19 | procedure TestParseNotifyWithParamJsonOK;
20 | procedure TestParseSuccessStrResultOK;
21 | procedure TestParseErrorOK;
22 | procedure TestParseErrorWithDataObjOK;
23 | procedure TestParseNoJsonrpcField;
24 | end;
25 |
26 | implementation
27 |
28 | uses
29 | superobject, TypInfo;
30 |
31 | function TTestJsonRpc.GetMessageTypeName(t: TJsonRpcObjectType): string;
32 | begin
33 | Result := GetEnumName(TypeInfo(TJsonRpcObjectType), Integer(t));
34 | end;
35 |
36 | procedure TTestJsonRpc.Setup;
37 | begin
38 | Self.FailsOnMemoryLeak := true;
39 | end;
40 |
41 | procedure TTestJsonRpc.TearDown;
42 | begin
43 |
44 | end;
45 |
46 | procedure TTestJsonRpc.TestParseErrorOK;
47 | const
48 | testMsg = '{ jsonrpc: "2.0", id:1, error: { code: -32600, message: "'
49 | + PRC_ERR_INVALID_REQUEST + '", data: "blabla" } }';
50 | var
51 | expected, actual: IJsonRpcParsedMessage;
52 | err: IJsonRpcError;
53 | begin
54 | expected := TJsonRpcParsedMessage.Create(jotError,
55 | TJsonRpcErrorObject.Create('1', TJsonRpcError.Create(-32600,
56 | PRC_ERR_INVALID_REQUEST, 'blabla')));
57 | actual := TJsonRpcMessage.Parse(testMsg, err);
58 | CheckEquals(expected.GetMessagePayload.AsJSon,
59 | actual.GetMessagePayload.AsJSon());
60 | CheckEquals(GetMessageTypeName(expected.GetMessageType),
61 | GetMessageTypeName(actual.GetMessageType));
62 | end;
63 |
64 | procedure TTestJsonRpc.TestParseErrorWithDataObjOK;
65 | const
66 | testMsg = '{ jsonrpc: "2.0", id:1, error: { code: -32600, message: "'
67 | + PRC_ERR_INVALID_REQUEST + '", '
68 | + 'data: {"method":"AUTH","params":{'
69 | + '"secretWord":"D4A0999956449F3A5DEA3EE29BA8AEBD", "appId":100},'
70 | + '"id":1,'
71 | + '"jsonrpc":"2.0"}'
72 | + ' } }';
73 | var
74 | expected, actual: IJsonRpcParsedMessage;
75 | err: IJsonRpcError;
76 | begin
77 | expected := TJsonRpcParsedMessage.Create(jotError,
78 | TJsonRpcErrorObject.Create('1', TJsonRpcError.Create(-32600,
79 | PRC_ERR_INVALID_REQUEST,
80 | SO('{"method":"AUTH","params":{'
81 | + '"secretWord":"D4A0999956449F3A5DEA3EE29BA8AEBD", "appId":100},'
82 | + '"id":1,"jsonrpc":"2.0"}'))));
83 | actual := TJsonRpcMessage.Parse(testMsg, err);
84 | CheckEquals(expected.GetMessagePayload.AsJSon,
85 | actual.GetMessagePayload.AsJSon());
86 | CheckEquals(GetMessageTypeName(expected.GetMessageType),
87 | GetMessageTypeName(actual.GetMessageType));
88 | end;
89 |
90 | procedure TTestJsonRpc.TestParseNoJsonrpcField;
91 | const
92 | testMsg = '{ method: "alarm_notify", params: { object: 102 } }';
93 | var
94 | expected, actual: IJsonRpcError;
95 | begin
96 | expected := TJsonRpcError.InvalidRequest(ERROR_NO_JSONRPC_FIELD);
97 | TJsonRpcMessage.Parse(testMsg, actual);
98 |
99 | CheckEquals(expected.AsJsonObject.AsJSon,
100 | actual.AsJsonObject.AsJSon());
101 | end;
102 |
103 | procedure TTestJsonRpc.TestParseNotifyWithParamJsonOK;
104 | const
105 | testMsg = '{"method":"ALARM",'
106 | + '"params":{'
107 | + ' "alarmTime":"2016-08-24T02:05:09.036Z",'
108 | + ' "alarmId":3,'
109 | + ' "alarmObject":2,'
110 | + ' "alarmSeqNo":0'
111 | + '},'
112 | + '"jsonrpc":"2.0"}';
113 | var
114 | expected, actual: IJsonRpcParsedMessage;
115 | err: IJsonRpcError;
116 | begin
117 | expected := TJsonRpcParsedMessage.Create(jotNotification,
118 | TJsonRpcNotificationObject.Create('ALARM', SO('{'
119 | + ' "alarmTime":"2016-08-24T02:05:09.036Z",'
120 | + ' "alarmId":3,'
121 | + ' "alarmObject":2,'
122 | + ' "alarmSeqNo":0'
123 | + '}')));
124 | actual := TJsonRpcMessage.Parse(testMsg, err);
125 | CheckEquals(expected.GetMessagePayload.AsJSon,
126 | actual.GetMessagePayload.AsJSon());
127 | CheckEquals(GetMessageTypeName(expected.GetMessageType),
128 | GetMessageTypeName(actual.GetMessageType));
129 | end;
130 |
131 | procedure TTestJsonRpc.TestParseRequestOK;
132 | const
133 | testMsg =
134 | '{"jsonrpc":"2.0",'
135 | + '"id":1491225202566,'
136 | + '"method":"AUTH",'
137 | + '"params":{'
138 | + ' "appId":901,'
139 | + ' "secretWord":"D4A0999956449F3A5DEA3EE29BA8AEBD"'
140 | + ' }'
141 | + '}';
142 | var
143 | expected, actual: IJsonRpcParsedMessage;
144 | err: IJsonRpcError;
145 | begin
146 | expected := TJsonRpcParsedMessage.Create(jotRequest,
147 | TJsonRpcRequestObject.Create('1491225202566', 'AUTH',
148 | SO('{"secretWord":"D4A0999956449F3A5DEA3EE29BA8AEBD","appId":901}')));
149 | actual := TJsonRpcMessage.Parse(testMsg, err);
150 |
151 | CheckEquals(GetMessageTypeName(expected.GetMessageType),
152 | GetMessageTypeName(actual.GetMessageType));
153 | CheckEquals(expected.GetMessagePayload.AsJSon,
154 | actual.GetMessagePayload.AsJSon());
155 | end;
156 |
157 | procedure TTestJsonRpc.TestParseSuccessStrResultOK;
158 | const
159 | alarmsJsonStr = '[{"id":503,"alarmId":3,"alarmObject":2,'
160 | + '"alarmTime":"2016-08-24T02:05:09.036Z"},{"id":2,"alarmId":2,'
161 | + '"alarmObject":1,"alarmTime":"2016-08-24T05:24:17.017Z"},'
162 | + '{"id":3,"alarmId":9,"alarmObject":3,'
163 | + '"alarmTime":"2016-08-24T08:07:22.115Z"}]';
164 | testMsg = '{"jsonrpc":"2.0","id":503,'
165 | + '"result":' + alarmsJsonStr + '}';
166 | var
167 | expected, actual: IJsonRpcParsedMessage;
168 | err: IJsonRpcError;
169 | begin
170 | expected := TJsonRpcParsedMessage.Create(jotSuccess,
171 | TJsonRpcSuccessObject.Create('503', SO(alarmsJsonStr)));
172 | actual := TJsonRpcMessage.Parse(testMsg, err);
173 |
174 | CheckEquals(GetMessageTypeName(expected.GetMessageType),
175 | GetMessageTypeName(actual.GetMessageType));
176 | CheckEquals(expected.GetMessagePayload.AsJSon,
177 | actual.GetMessagePayload.AsJSon());
178 | end;
179 |
180 | initialization
181 | TestFramework.RegisterTest(TTestJsonRpc.Suite);
182 |
183 | end.
184 |
185 |
--------------------------------------------------------------------------------
/test/testjsonrpcerrors.pas:
--------------------------------------------------------------------------------
1 | unit testjsonrpcerrors;
2 |
3 | interface
4 |
5 | uses
6 | Windows, SysUtils, Classes, TestFramework, TestExtensions;
7 |
8 | type
9 | TTestJsonRpcError = class(TTestCase)
10 | protected
11 | procedure SetUp; override;
12 | procedure TearDown; override;
13 |
14 | published
15 | procedure TestErrorHasDataJsonCreated;
16 | procedure TestErrorHasDataAsStringCreated;
17 | procedure TestParseErrorCreated;
18 | procedure TestInvalidRequestHasDataJsonCreated;
19 | procedure TestInvalidRequestHasDataAsStrCreated;
20 | procedure TestMethodNotFoundHasDataJsonCreated;
21 | procedure TestMethodNotFoundHasDataAsStrCreated;
22 | procedure TestInvalidParamsHasDataJsonCreated;
23 | procedure TestInvalidParamsHasDataAsStrCreated;
24 | procedure TestInternalErrorHasDataJsonCreated;
25 | procedure TestInternalErrorHasDataAsStrCreated;
26 | end;
27 |
28 | implementation
29 |
30 | uses
31 | superobject, ujsonrpc2;
32 |
33 | procedure TTestJsonRpcError.Setup;
34 | begin
35 |
36 | end;
37 |
38 | procedure TTestJsonRpcError.TearDown;
39 | begin
40 |
41 | end;
42 |
43 | procedure TTestJsonRpcError.TestErrorHasDataAsStringCreated;
44 | var
45 | expected: ISuperObject;
46 | actual: IJsonRpcError;
47 | begin
48 | expected := SO();
49 | expected.I['code'] := -32201;
50 | expected.S['message'] := 'Authentification error';
51 | expected.I['data'] := 901;
52 | actual := TJsonRpcError.Error(-32201, 'Authentification error', SO(901));
53 | CheckEquals(expected.AsJSon(true), actual.asJsonObject.AsJSon(true));
54 | end;
55 |
56 | procedure TTestJsonRpcError.TestErrorHasDataJsonCreated;
57 | var
58 | expected: ISuperObject;
59 | actual: IJsonRpcError;
60 | begin
61 | expected := SO();
62 | expected.I['code'] := -32201;
63 | expected.S['message'] := 'Authentification error';
64 | expected.O['data'] := SO('{appId:901}');
65 | actual := TJsonRpcError.Error(-32201, 'Authentification error',
66 | SO('{appId:901}'));
67 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
68 | end;
69 |
70 | procedure TTestJsonRpcError.TestInternalErrorHasDataAsStrCreated;
71 | var
72 | expected: ISuperObject;
73 | actual: IJsonRpcError;
74 | begin
75 | expected := SO();
76 | expected.I['code'] := -32603;
77 | expected.S['message'] := RPC_ERR_INTERNAL_ERROR;
78 | expected.S['data'] := 'abc';
79 | actual := TJsonRpcError.InternalError('abc');
80 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
81 | end;
82 |
83 | procedure TTestJsonRpcError.TestInternalErrorHasDataJsonCreated;
84 | var
85 | expected: ISuperObject;
86 | actual: IJsonRpcError;
87 | begin
88 | expected := SO();
89 | expected.I['code'] := -32603;
90 | expected.S['message'] := RPC_ERR_INTERNAL_ERROR;
91 | expected.O['data'] := SO('{a: 1}');
92 | actual := TJsonRpcError.InternalError(SO('{a: 1}'));
93 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
94 | end;
95 |
96 | procedure TTestJsonRpcError.TestInvalidParamsHasDataAsStrCreated;
97 | var
98 | expected: ISuperObject;
99 | actual: IJsonRpcError;
100 | begin
101 | expected := SO();
102 | expected.I['code'] := -32602;
103 | expected.S['message'] := RPC_ERR_INVALID_PARAMS;
104 | expected.S['data'] := 'abc';
105 | actual := TJsonRpcError.InvalidParams('abc');
106 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
107 | end;
108 |
109 | procedure TTestJsonRpcError.TestInvalidParamsHasDataJsonCreated;
110 | var
111 | expected: ISuperObject;
112 | actual: IJsonRpcError;
113 | begin
114 | expected := SO();
115 | expected.I['code'] := -32602;
116 | expected.S['message'] := RPC_ERR_INVALID_PARAMS;
117 | expected.O['data'] := SO('{a: 1}');
118 | actual := TJsonRpcError.InvalidParams(SO('{a: 1}'));
119 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
120 | end;
121 |
122 | procedure TTestJsonRpcError.TestInvalidRequestHasDataAsStrCreated;
123 | var
124 | expected: ISuperObject;
125 | actual: IJsonRpcError;
126 | begin
127 | expected := SO();
128 | expected.I['code'] := -32600;
129 | expected.S['message'] := PRC_ERR_INVALID_REQUEST;
130 | expected.S['data'] := 'abc';
131 | actual := TJsonRpcError.InvalidRequest('abc');
132 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
133 | end;
134 |
135 | procedure TTestJsonRpcError.TestInvalidRequestHasDataJsonCreated;
136 | var
137 | expected: ISuperObject;
138 | actual: IJsonRpcError;
139 | begin
140 | expected := SO();
141 | expected.I['code'] := -32600;
142 | expected.S['message'] := PRC_ERR_INVALID_REQUEST;
143 | expected.O['data'] := SO('{a: 1}');
144 | actual := TJsonRpcError.InvalidRequest(SO('{a: 1}'));
145 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
146 | end;
147 |
148 | procedure TTestJsonRpcError.TestMethodNotFoundHasDataAsStrCreated;
149 | var
150 | expected: ISuperObject;
151 | actual: IJsonRpcError;
152 | begin
153 | expected := SO();
154 | expected.I['code'] := -32601;
155 | expected.S['message'] := PRC_ERR_METHOD_NOT_FOUND;
156 | expected.S['data'] := 'test';
157 | actual := TJsonRpcError.MethodNotFound('test');
158 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
159 | end;
160 |
161 | procedure TTestJsonRpcError.TestMethodNotFoundHasDataJsonCreated;
162 | var
163 | expected: ISuperObject;
164 | actual: IJsonRpcError;
165 | begin
166 | expected := SO();
167 | expected.I['code'] := -32601;
168 | expected.S['message'] := PRC_ERR_METHOD_NOT_FOUND;
169 | expected.O['data'] := SO('{a: 1}');
170 | actual := TJsonRpcError.MethodNotFound(SO('{a: 1}'));
171 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
172 | end;
173 |
174 | procedure TTestJsonRpcError.TestParseErrorCreated;
175 | var
176 | expected: ISuperObject;
177 | actual: IJsonRpcError;
178 | begin
179 | expected := SO();
180 | expected.I['code'] := -32700;
181 | expected.S['message'] := RPC_ERR_PARSE_ERROR;
182 | expected.S['data'] := 'test';
183 | actual := TJsonRpcError.ParseError('test');
184 | CheckEquals(expected.AsJSon, actual.asJsonObject.AsJSon());
185 | end;
186 |
187 | initialization
188 | TestFramework.RegisterTest(TTestJsonRpcError.Suite);
189 |
190 | end.
191 |
192 |
--------------------------------------------------------------------------------